Hibernate的抓取策略总结
今天在做hibernate的性能优化的时候,hibernate的抓取策略又派上用场了,于是顺便总结了一下并作了如下记录。
?
hibernate的抓取策略通常有下面四种:
?
??? ?1.连接抓取(Join fetching) ,即Hibernate通过 在select语句使用outer join(外连接)来 获得对象的关联实例或? 者关联集合.
?
??? ?2.查询抓取(Select fetching) ,即另外发送一条 select 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句.
?
???? 3.子查询抓取(Subselect fetching) ,即 另外发送一条select 语句抓取在前面查询到?的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条
select语句 .
????? 4.批量抓取(Batch fetching) ,这种策略跟查询抓取本质上是一样的,只不过是 对查询抓取的优化而已, 通过指定一个主键或外键 列表,Hibernate使用单条select语句获取一批对象实例或集合.
?
?Join fetching , Select fetching 与 Batch-size 可以为单个实体的抓取进 行性能优化;
?Join fetching , Select fetching ,Subselect fetching , Batch fetching 都可以为集合的抓取进行性能优化;
?
下面将以一个多对一双向关联映射(多个员工属于同一部门)进行说明:
?
关联映射后的关系模型:
?t_employee(id int pk, name varchar, departmentid int fk->t_department(id))
?t_department(id int pk, name varchar)
?
实体模型:
?com.lrh.hibernate.Employee(int id, String name, Department department)
?com.lrh.hibernate.Department(int id, String name, Set employees)
?
配置文件:
? <!-- com.lrh.hibernate/Employee.hbm.xml -->
?
? <hibernate-mapping>?
????? <class name="com.lrh.hibernate.Employee" table="t_employee">?
????????? <id name="id"><generator column="departmentid"/>?
????? </class>?
?</hibernate-mapping>
?
? <!-- com.lrh.hibernate/Department.hbm.xml -->
?
? <hibernate-mapping>?
????? <class name="com.lrh.hibernate.Department" table="t_department">?
????????? <id name="id"><generator inverse="true" >?
????????????? <!-- <key>指定引用至自身的外键表(t_employee)中的外键 -->
???????????? <key column="departmentid"/>?
????????????? <!-- <one-to-many>映射一对多关系 -->
????????????? <one-to-many -->
??? <set name="employees" inverse="true" fetch="join">?
?????? <key column="departmentid"/>?
?????? <one-to-many -->
??? <set name="employees" inverse="true" fetch="select">?
?????? <key column="departmentid"/>?
?????? <one-to-many fetch="subselect" /> )使用一条 Select 语句一次性抓取出来, 这样减少了与数据库的交互次数, 一次将每个对象的集合都给初始化了;subselect 只在 <set> 集合中出现 。
?
? 使用连接抓取的com.lrh.hibernate/Department.hbm.xml配置文件修改<set></set>节点如下:
??? <!--添加fetch="subselect" -->
??? <set name="employees" inverse="true" fetch="subselect">?
?????? <key column="departmentid"/>?
?????? <one-to-many fetch="select" batch-size="2" />? 当初始化一个 Department 的 Employee 集合的时候, Hibernate 还是发出了一条SQL 语句,跟查询抓取不同的是:这条 SQL 与是通过指定了 Employee 表中的 departmentid 外键列表(2个),Hibernate 会以一条 SQL 语句初始化 batch-size 指定的数量的 Employee 集合;即根据batch-size 分成了两组(一组有2个 Department id 值的列表,第二组只有1个)来初始化 Employee 集合。
?
? 使用连接抓取的com.lrh.hibernate/Department.hbm.xml配置文件修改<set></set>节点如下:
??? <!--添加fetch="select" batch-size="2"-->
??? <set name="employees" inverse="true" fetch="select"? batch-size="2">?
?????? <key column="departmentid"/>?
?????? <one-to-many class="com.lrh.hibernate.Employee"/>?
??? </set>??
?
??测试核心代码:
???? List results = session.createQuery("From Department d where d.id in (1,2,3)").list();?
??? ?Department d = (Department)results.get(0);?
???? System.out.println(d.getEmployees.size());
?