Hibernate 的数据加载方式:
在JDBC的操作中,利用SQL语句加载所需要的数据进行处理,当SQL提交之后,这些数据就被读取待用;
在Hibernate中,我们有更多的选择;HIbernate中的数据记载方式:
- 及时加载(Immeddiate Loading)
当实体加载完后,立即加载其相关联数据;
- 延迟加载(Lazy Loading)
实体加载时,并不会立即加载其数据,而是当第一次访问的时候,在进行读取;
- 预先加载(Eager Loading)
实体与其关联对象同时读取,这与即时加载类似,不过实体及其相关数据是通过一条SQL语句读取到得!(基于外连接);
- 批量加载(Batch Loading)
对于即时加载和延迟加载,可以采用批量加载方式进行性能上的优化;
测试:
及时加载:
private static void queryTest() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
final String hql = "from TUser where name = 'keith'";
List<TUser> users = session.createQuery(hql).list();
System.out.println("query finished!!!");
Iterator<TUser> it = users.iterator();
while (it.hasNext()) {
TUser user = it.next();
System.out.println("user's name:"+user.getName());
System.out.println("user's address:"+user.getAddresses().size());
}
session.getTransaction().commit();
}
看下SQL的执行顺序:
select tuser0_.userid as userid1_, tuser0_.name as name1_ from TUser tuser0_ where tuser0_.name='keith'
select addresses0_.user_id as user3_1_1_,addresses0_.addressId as addressId1_,addresses0_.addressId as addressId0_0_,addresses0_.info as info0_0_ from TAddress addresses0_ where addresses0_.user_id=?
query finished!!!
user's name:keith
user's address:2
首先会加载实体类的所有内容,然后在加载其相关的数据!
延迟加载:
在及时加载中,当Hibernate加载TUser对象时,即同时加载了其所关联的TAddress对象,这样就可能会导致性能的降低,例如:我们只想要TUser的信息,并不想要TAddress的信息,如果按照及时加载的话,就将TAddress又查询了,导致性能降低!如果用延迟加载就可以解决这一问题;
延迟加载只需要在<set />标签中加个属性即可:
<set name="addresses" cascade="all" lazy="true"> <key column="user_id" /> <one-to-many class="TAddress"/> </set>
看下SQL的执行顺序:
select tuser0_.userid as userid1_, tuser0_.name as name1_ from TUser tuser0_ where tuser0_.name='keith'
query finished!!!
user's name:keith
select addresses0_.user_id as user3_1_1_,addresses0_.addressId as addressId1_,addresses0_.addressId as addressId0_0_,addresses0_.info as info0_0_ from TAddress addresses0_ where addresses0_.user_id=?
什么时候需要它,什么时候才发SQL查询它!
预先加载:
预先加载通过outer-join完成关联数据的加载,这样,通过一条SQL即可完成实体及其关联数据的读取操作 ,如果要是多条数据的话,这样会节省很大的资源;不过在集合类型中(一对多,多对一,或者多对多关系中),不推荐采用预先加载方式,对于集合,如果条件允许,我们应该尽量避免延迟加载;以避免性能生的不必要开销!
一般来说,outer-join可以高效的处理关联数据。但在一些特殊的情况下,特别是比较复杂的关联关系情况下;如多层管理,hibernate生成的的outer-join可能复杂,此时我们应该根据情况判断采用预先加载在当前环境的可用性;同时也可以通过调整全局变量限定outer-join的层次;
批量加载 :
是通过批量提交多个限定条件,一次完成多个SQL的读取;
当我们在被查询的类上添加一个 batch-size="3"属性时,指定批量查询的数量;就可以进行批量查询;
我们对TUser进行批量查询,其*.hbm.xml这样:
<hibernate-mapping package="com.keith.dataLoad"> <class name="TUser" table="TUser" batch-size="3"> <id name="userid"> <generator class="native" /> </id> 。。。。 </class> </hibernate-mapping>
我们的测试类这样写:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
final String hql = "from TUser";
List<TUser> users = session.createQuery(hql).list();
Iterator it = users.iterator();
while (it.hasNext()) {
TUser user = (TUser) it.next();
System.out.println(user);
}
session.getTransaction().commit();
但是会发出2条SQL;(因为我的SQL里就有2条数据)
输出结果:
com.keith.dataLoad.TUser@8ae45a
com.keith.dataLoad.TUser@29c204