1,数据加载
1),Session.get/load
区别:(1),未发现符合条件的记录:get-->null,load-->ObjectNotFoundException。
(2),load可返回实体的代理类实例,get永远直接返回实体类。
(3),load-->内部缓存-->二级缓存-->SQL(DB),get-->内部缓存-->SQL(DB)。
Session加载实体对象时经过的过程:
内部缓存(查找数据)-->NonExists(查找查询条件)-->第二级缓存(load方法)-->Select SQL(DB)-->根据Result创建对应的数据对象-->将其数据对象纳入当前Session实体管理容器(内部缓存)-->执 行Interceptor.onLoad-->纳入二级缓存-->如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad 方法-->返回数据对象。
2),Session.find/iterate
Session.find()------->session.createQuery().list()-----无法利用缓存,它对缓存只写不读。
Session.iterate()---->session.createQuery().iterate()-----可以充分利用缓存。
-------基于充分利用缓存以提升性能上的考量。
内存使用上的考虑:对海量数据进行操作,find方法一次获得所有的记录并将其读入内存-->内存消耗甚至OutOfMemoryError。
解决方案之一:逐条对记录进行处理,将内存消耗保持在可以接受的范围之内。
String hql = "from TUser where age > ?";
Iterator it = session.iterate(hql,new Integer(18),Hibernate.INTEGER);
while(it.hasNext()){
TUser user = (TUser)it.next();
session.evict(user);//将对象从一级缓存中移除
sessionFactory.evict(TUser.class,user.getId());//将对象从二级缓存中移除
}
解决方案之二:SQL或存储过程。
3),Query Cache
---中保存了之前查询操作执行过的Select SQL,以及由此查询产生的查询结果集(包括查询对象的类型和id)。
根据查询SQL--->从Query Cache中检索--->取出这个SQL的检索结果集--->根据这个结果集中对象类型及其id,从缓存中取出对赢得实体对象返回。
Query Cache只在特定的情况下产生作用:
(1),完全相同的Select SQL重复执行。
(2),在两次查询之间,此Select SQL对应的库表没有发生过改变。
<hibernate-configuration>
<session-factory>
....
<property name="hibernate.cache.use_query_cache">true</property>
....
</session-factory>
<hibernate-configuration>
String hql="from TUser where age > ?";
Query query = session,createQuery(hql).setInteger(0,20);
query.setCacheable(true);
List userList = query.list();
int len = userList.size();
for(int i=0;i<len;i++){
TUser user = (TUser)userList.get(i);
}
query = session2.createQuery(hql).setInteger(0,20);
query.setCacheable(true);//第二次查询时,也必须将Cacheable设为true
userList = query.list();
len = userList.size();
for(int i=0;i<len;i++){
TUser user = (TUser)userList.get(i);
}
看到第二次查询时,Hibernate并没有执行任何Select SQL即完成了任务,这就是Query Cache的作用。
4),延迟加载(Lazy Loading)
---为了避免在某些情况下,关联关系所带来的无谓的性能开销。---即在需要数据的时候,才真正执行数据加载操作。
Hibernate2延迟加载实现主要针对:(1),实体对象;(2),集合。
Hibernate3同时提供了属性的延迟加载功能。
(1),实体对象的延迟加载
<class ... laze="true"> ---Hibernate2中,laze属性默认为false,Hibernate3中其默认值为true。
Hibernate的代理机制:Hibernate中引入了CGLib作为代理机制实现的基础。CGLib可以在运行期动态生成Java Class,这里的代理机制,其基本实现原理就是通过由CGLib构造一个包含目标对象所有属性和方法的动态对象(相当于动态构造目标对象的一个字类)返 回,并以之作为中介,为目标对象提供更多的特性。真正的TUser对象位于代理类的CGLIB$CALLBACK_0.target属性中。
-----只有当客户程序真正调用实体类的取值方法时,Hibernate才会执行数据库查询操作。
(2),集合类型的延迟加载
<set ... lazy="true">
Hibernate.initialize方法可以强制Hibernate立即加载关联对象集。
Hibernate.initialize(user.getAddresses());
session.close();
//通过Hibernare.initialize方法强制读取数据,addresses对象即可脱离session进行操作
Set hset = user.getAddresses();
TAddress addr = (TAddress)hset.toArray()[0];
(3),属性的延迟加载
<property ... lazy="true">
与实体和集合类型的延迟加载不同,Hibernate3属性延迟加载机制在配置之外,还需要借助类增强器对二进制Class文件进行强化处理。
5),数据保存
Session.save方法用于实体对象到数据库的持久化操作。
包含步骤:在Session内部缓存中寻找待保存对象-->lifecycle(onSave())-->Validatable (validate())-->Interceptor.onSave()-->构造Insert SQL-->user.id=new id-->将user对象放入内部缓存-->对级联关系进行递归处理。
Session.update:根据待更新实体对象的Key在当前session的内部缓存中进行查找(一个Persistent实体对象调用update并不会产生作用)-->初始化实体对象的状态信息(作为之后脏数据检查的依据),并将其纳入内部缓存。
Session.saveOrUpdate:实际上是save和update方法的组合应用,它本身并没有增加新的功能特性,但是却为我们的应用层开发提供了一个相当便捷的功能选择。--无需关心传入的user参数到底是怎样的状态。
public interface IUserDAO{
public TUser getUser(String id);
public void saveUser(TUser user);
}
6),数据批量操作
(1),数据批量导入
<session-factory>
...
<property name="hibernate.jdbc.batch_size">25</property>
...
</session.factory>
public void importUserList() throws HibernateException{
Transaction tx = session.beginTransaction();
for(int i=0;i<10000;i++){
TUser user = new TUser();
user.setName("user" + i);
session.save(user);
if(i%25==0){ //以每25个数据作为一个处理单元
session.flush();
session.clear();
}
}
tx.commit();
}
(2),数据批量删除
内存消耗:
Transaction tx = session.beginTransaction();
String hql = "from TUser";
Query query = session.createQuery(hql);
ScrollableResults scRes = query.scroll();
while(scRes.next()){
TUser user = (TUser)scRes.get(0);
session.delete(user);
}
tx.commit();
迭代删除操作的执行效率:采用调整hibernate.jdbc.batch_size参数来解决。
BULK delete/update:
Transaction tx = session.beginTransaction();
String hql = "delete TUser";
Query query = session.createQuery(hql);
int ret = query.executeUpdate();
tx.commit();
--------批量删除与缓存管理的矛盾仍然存在。---关闭二级缓存,调用不同session解决内部缓存带来的问题。
7),Collection
(1),Collection类型(org.hibernate.collection)
无序集:Set,Bag,Map
有序集:List
---无序与有序,是针对Hibernate数据持久过程中,是否保持数据集合中的记录排列输序加以区分的。
Set:
陷阱--->
<set name="addresses" table="t_address" lazy="false">
<key column="user_id"/>
<one-to-many class="TAddress"/>
</set>
<set name="addresses" table="t_address" lazy="false">
<key column="user_id"/>
<element type="string" column="address"/>
</set>
Bag:允许包含重复元素的“Set”。---基于List但屏蔽其有序性。
idbag:
<idbag name="addresses" lazy="true" table="t_address">
<collection-id type="int" column="id">
<generator class="identity"/>
</collention-id>
<key column="user_id">
<element type="string" column="address"/>
</idbag>
Map:键值对应关系。
<map name="addresses" lazy="true" table="t_address">
<key column="user_id"/>
<index type="string" column="type"/>
<element type="string" column="address"/>
</map>
index:要求在数据集中取值唯一。
TUser user = (TUser)session.load(TUser.class,new Integer(1));
user.getAddresses().get("Home");//读取家庭地址
user.getAddresses().get("Office");//读取办公地址
List:实现了集合内元素顺序的持久化。
<list name="addresses" lazy="true" table="t_address">
<key column="user_id"/>
<index type="integer" column="idx"/>
<element type="string" column="address"/>
</list>
8),结果集排序
排序强调的是针对现有数据,以特定的逻辑对其排列此序进行调整,而排序的结果,是数据在内存中的某种排列次序,属于临时状态。
排序方式:
Sort--->Collection中的数据排序,如对一个List中的元素先后进行排序调整。(JVM)
<set ... sort="natural".../>
如果期望指定某种特殊的排序算法,那么可以实现java.util.Comparator接口,如:
package org.sample
public class LengthComparator implements Comparator{
public int compare(Object obj1,Object obj2){
String str1 = String.valueOf(Obj1);
String str2 = String.valueOf(Obj2);
return str1.length()-str2.length();
}
}
<set ... sort="org.sample.LengthComparator".../>
---Bag,List不支持sort排序方式。
order-by--->对数据库执行Select SQL时,由order by子句实现的数据排序方式。(数据库)
<set ... order-by="address desc".../>
List不支持order-by排序。