1. Session---单数据加载---load/ get
Load方法根据指定的实体类和id从数据库装载认为存在的一条记录. 应该确保对象确实存在, 否则会抛出ObjectNotFoundException.
Load方法可返回实体的代理类实例, 可充分利用内部缓存和二级缓存中的现有数据.
get方法根据指定的实体类和id从数据库查询并装载一条记录.数据不存在将得到null.
get方法返回的永远是实体类. 只在内部缓存中进行数据查找, 如果没有数据就调用SQL完成数据读取.
- 出于性能考虑,避免无谓的数据库访问,Session在调用数据库查询功能之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,如果第一级缓存查找命中,且数据状态合法,则直接返回。
- 之后,Session会在当前 “NonExists”记录中进行查找,如果 “NonExists”记录中存在同样的查询条件,则返回null。“NonExists”记录了当前 Session实例在之前所有查询操作中,未能查询到有效数据的查询条件。如果Session中一个无效的查询条件重复出现,即可迅速做出判断。
- 对于load方法而言,如果内部缓存中没有发现有效数据,则查询第二级缓存,如果第二级缓存命中,则返回。
- 如果在缓存中未发现有效数据,则发起数据库查询操作(Select SQL).
- 如果经过查询未发现对应记录,则将此次查询的信息在 “NonExists”中加以记录,并返回null。
- 否则根据映射配置和Select SQL得到的 ResultSet,创建对应的数据对象. 并将其数据对象纳入当前Session实体管理容器(一级缓存)。
- 执行Interceptor.onLoad方法(如果有对应的Intercepeor)。
- 将数据对象纳入二级缓存。
- 如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad方法。
- 返回数据对象。
2. Session---批量数据查询---find/iterate|createQuery().list/iterate
Hibernate2的find/iterate分别返回list和Iterator, Hibernate3中,上述方法已经从Session接口中废除,统一由Query接口提供。Hibernate3将Session的createQuery()方法得到的Query对象调用list/iterate方法实现相同的功能. 从实现体制而言,这两个版本之间并没有什么差异。
find/ list方法通过一条select sql实现查询; 而iterate则执行1+ N次查询, 它首先执行select sql获取满足条件的id, 再根据每个id获取对应的记录.
find方法将执行Select HQL从数据库中获得所有符合条件的记录并构造相应的实体对象,实体对象构建完毕之后,就将其纳入缓存。为之后的iterate方法提供了现成的可用数据。
这样,之后iterate方法执行时,它首先执行一条Select SQL以获得所有符合查询条件的数据id,随即,iterate方法首先再本地缓存中根据id查找对应的实体对象是否存在(类似Session.load方法),如果缓存中已经存在对应的数据,则直接以此数据对象作为查询结果,如果没找到,再执行相应的Select语句获得对应的库表记录(iterate方法如果执行了数据库读取操作并构建了完整的数据对象,也会将其查询结果纳入缓存)。
根据java面向对象的继承层次,Object是所有类的父类,所以使用面对对象的持久化框架Hibernate可以执行下述操作:
public static void testHibernateOO() { Session s = HibernateSession3.getSession(); Iterator<Object> itor =(Iterator<Object>)s.createQuery("FROM java.lang.Object").list(); while(itor.hasNext()){ Object rowData = itor.next(); System.out.println(rowData.getClass()+":"); } }
3. Session批量数据查询与缓存利用的示例
如果执行下面的代码:
Tuser data =null; Iterator<Tuser> dataItor = hibernate_session.createQuery(" From Tuser").iterate(); while(dataItor.hasNext()){ data = dataItor.next(); System.out.println("iterate:" + data.getName() + ":" + data.getEmail()); } Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_ user tuser0_ where tuser0_.id=? iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com] Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_ user tuser0_ where tuser0_.id=? iterate:Washing:[aisee@163.com]
如果执行下面的代码:
Tuser data =null;
List<Tuser> datas = hibernate_session.createQuery(" From Tuser").list();
for(int i=0;i<datas.size();i++){
data = datas.get(i);
System.out.println("list:" + data.getName() + ":" + data.getEmail());
}
System.out.println("\r\nUse iterate");
Iterator<Tuser> dataItor = hibernate_session.createQuery(" From Tuser").iterate();
while(dataItor.hasNext()){
data = dataItor.next();
System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user t
user0_
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
iterate:Washing:[aisee@163.com]
如果执行下面的代码:
Tuser data =null; List<Tuser> datas = hibernate_session.createQuery(" From Tuser").list(); for(int i=0;i<datas.size();i++){ data = datas.get(i); System.out.println("list:" + data.getName() + ":" + data.getEmail()); } System.out.println("\r\nUse iterate"); Iterator<Tuser> dataItor = hibernate_session.createQuery(" From Tuser"). iterate(); while(dataItor.hasNext()){ data = dataItor.next(); System.out.println("iterate:" + data.getName() + ":" + data.getEmail()); } System.out.println("\r\nUse list AGAIN"); datas = hibernate_session.createQuery(" From Tuser").list(); for(int i=0;i<datas.size();i++){ data = datas.get(i); System.out.println("list:" + data.getName() + ":" + data.getEmail()); }
Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user t
user0_
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
iterate:Washing:[aisee@163.com]
Use list AGAIN
Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user t
user0_
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
Use list
Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user t
user0_
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
如果执行:
Tuser data =null; System.out.println("\r\nUse list"); List<Tuser> datas = hibernate_session.createQuery(" From Tuser").list(); for(int i=0;i<datas.size();i++){ data = datas.get(i); System.out.println("list:" + data.getName() + ":" + data.getEmail()); } hibernate_session.close(); hibernate_session = MySessionFactory.getSession(); System.out.println("\r\nUse iterate"); Iterator<Tuser> dataItor = hibernate_session.createQuery(" From Tuser").iterate(); while(dataItor.hasNext()){ data = dataItor.next(); System.out.println("iterate:" + data.getName() + ":" + data.getEmail()); } System.out.println("\r\nUse list AGAIN"); datas = hibernate_session.createQuery(" From Tuser").list(); for(int i=0;i<datas.size();i++){ data = datas.get(i); System.out.println("list:" + data.getName() + ":" + data.getEmail()); }
Use list
Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user t
user0_
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:Washing:[aisee@163.com]
Use list AGAIN
Hibernate: select tuser0_.id as id2_, tuser0_.name as name2_, tuser0_.email as email2_ from T_user t
user0_
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
如果执行下面的代码:
System.out.println("\r\nUse iterate");
Iterator<Tuser> dataItor = hibernate_session.createQuery(" From Tuser").iterate();
while(dataItor.hasNext()){
data = dataItor.next();
System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
System.out.println("\r\nUse iterate AGAIN");
dataItor = hibernate_session.createQuery(" From Tuser").iterate();
while(dataItor.hasNext()){
data = dataItor.next();
System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:Washing:[aisee@163.com]
Use iterate AGAIN
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
iterate:Washing:[aisee@163.com]
如果执行下面的代码:
System.out.println("\r\nUse iterate");
Iterator<Tuser> dataItor = hibernate_session.createQuery(" From Tuser").iterate();
while(dataItor.hasNext()){
data = dataItor.next();
System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
hibernate_session.close();
hibernate_session = MySessionFactory.getSession();
System.out.println("\r\nUse iterate AGAIN");
dataItor = hibernate_session.createQuery(" From Tuser").iterate();
while(dataItor.hasNext()){
data = dataItor.next();
System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:Washing:[aisee@163.com]
Use iterate AGAIN
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
Hibernate: select tuser0_.id as id2_0_, tuser0_.name as name2_0_, tuser0_.email as email2_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:Washing:[aisee@163.com]
find方法(hibernate2)/Query的list(hibernate3)实际上不利用缓存,它对缓存只写不读。而iterate方法(hibernate2)/Query的iterate(hibernate3)则可以充分发挥缓存带来的优势,如果目标数据只读或者读取相对较为频繁,通过这种机制可以大大减少性能上的损耗。对于批量数据, hibernate可以自动延迟加载:
把数据库数据扩大后:
String hsql = " From Tuser as t where t.id<501";
Tuser data =null;
long end =0;
System.out.println("\r\nUse iterate");
long begin =System.currentTimeMillis();
Iterator<Tuser> dataItor = hibernate_session.createQuery(hsql).iterate();
end =System.currentTimeMillis();
System.out.println("Time be userd:"+(end-begin));
while(dataItor.hasNext()){
data = dataItor.next();
System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ where tuser0_.id<501
Time be userd:15
Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.email as email0_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:AiSee11652:[1w@11, 1w@11, as@tsts.com]
Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.email as email0_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:Washing:[aisee@163.com]
Hibernate: select tuser0_.id as id0_0_, tuser0_.name as name0_0_, tuser0_.email as email0_0_ from T_
user tuser0_ where tuser0_.id=?
iterate:Washing:[aisee@163.com]
....
执行:
String hsql = " From Tuser as t where t.id<100001";
Tuser data =null;
System.out.println("\r\nUse list");
long end =0;
long begin =System.currentTimeMillis();
System.out.println("\r\nUse iterate");
begin =System.currentTimeMillis();
Iterator<Tuser> dataItor = hibernate_session.createQuery(hsql).iterate();
while(dataItor.hasNext()){
data = dataItor.next();
//System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
end =System.currentTimeMillis();
System.out.println("Time be userd:"+(end-begin));
System.out.println("\r\nUse iterate AGAIN");
begin =System.currentTimeMillis();
dataItor = hibernate_session.createQuery(hsql).iterate();
while(dataItor.hasNext()){
data = dataItor.next();
//System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
}
end =System.currentTimeMillis();
System.out.println("Time be userd:"+(end-begin));
Use list
Use iterate
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ where tuser0_.id<100001
Time be userd:4078
Use iterate AGAIN
Hibernate: select tuser0_.id as col_0_0_ from T_user tuser0_ where tuser0_.id<100001
Time be userd:3797
如果是用list, 不会利用任何缓存,更不会延迟加载:
System.out.println("\r\nUse list");
long end =0;
long begin =System.currentTimeMillis();
List<Tuser> datas = hibernate_session.createQuery(hsql).list();
end =System.currentTimeMillis();
System.out.println("Time be userd:"+(end-begin));
for(int i=0;i<datas.size();i++){
data = datas.get(i);
System.out.println("list:" + data.getName() + ":" + data.getEmail());
}
Use list
Hibernate: select tuser0_.id as id0_, tuser0_.name as name0_, tuser0_.email as email0_ from T_user t
user0_ where tuser0_.id<501
Time be userd: 78
list:AiSee11652:[1w@11, 1w@11, as@tsts.com]
list:Washing:[aisee@163.com]
list:Washing:[aisee@163.com]
list:Washing:[aisee@163.com]
list:Washing:[aisee@163.com]
list:Washing:[aisee@163.com]
如果数据量较大, 结合iterate方法和Session/SessionFactory的evict方法逐条对记录进行处理,并将数据对象强制从缓存中移除, 将内存消耗保持再可以接受的范围之内。查询50万条:
System.out.println("\r\nUse iterate");
begin =System.currentTimeMillis();
Iterator<Tuser> dataItor = hibernate_session.createQuery(hsql).iterate();
while(dataItor.hasNext()){
data = dataItor.next();
data.getName();
//System.out.println("iterate:" + data.getName() + ":" + data.getEmail());
hibernate_session.evict(data);
factory.evict(Tuser.class,data.getId());
}
end =System.currentTimeMillis();
System.out.println("Time be userd:"+(end-begin));
Use iterate
Time be userd:2113969
直接查询并保存在缓存:
System.out.println("\r\nUse iterate");
begin =System.currentTimeMillis();
Iterator<Tuser> dataItor = hibernate_session.createQuery(hsql).iterate();
while(dataItor.hasNext()){
data = dataItor.next();
data.getName();
//out.println("iterate:" + data.getName() + ":" + data.getEmail());
// hibernate_session.evict(data);
// factory.evict(Tuser.class,data.getId());
}
end =System.currentTimeMillis();
System.out.println("Time be userd:"+(end-begin));
out.println("Time be userd:"+(end-begin)+"<br />");
Use iterate
ERROR: 2007-01-13 20:55:28,687: StandardWrapperValve[line:253}: Servlet.service() for servlet jsp th
rew exception
java.lang.OutOfMemoryError: Java heap space
所以数据量过大, 应该避免使用find(list), 而使用iterate(iterate),并且手动清除hibernate的一,二级缓存。
4. Query Cache(阑尾)
Query Cache中保存了之前查询操作执行过的Select SQL,以及由此查询产生的查询结果集 (包括查询对象的类型和id)。
之后发生查询请求的时候,Hibernate会首先根据查询的 SQL从Query Cache中检索,如果此SQL曾经执行过,则取出对应这个SQL的检索结果集,再根据这个结果集中的对象类型及其id,从缓存中取出对应的实体对象返回。
Query Cache中缓存的SQL及其结果集并非永远存在,当Hibernate发现此SQL对应的库表发生了变动(Update/Delete/Insert),会自动将Query Cache中对应表的 SQL缓存废除。因此,Query Cache只在特定的情况下产生作用:
- 完全相同的Select SQL重复执行。
- 再两次查询之间,此Select SQL对应的库表没有发生过改变。
由于以上两个条件的严格限制,Query Cache再实际应用中的意义并没有我们想象中的那么重大,因此,Hibernate在默认情况下也关闭了这个特性。
为了启用Query Cache,我们必须在Hibernate配置文件(hibernate.cfg.xml)中打开配置hibernate.cache.use_query_cache为ture,之后我们必须在Query 的查询执行之前, 调用Query的setQureyCache(true); 而且后面的查询想利用该缓存也需要调用Query的setQureyCache(true). 这样find(list)就可以利用Query Cache缓存了.
鉴于配置和使用比较麻烦, 所以用得不多.
5. Hibernate2的find/iterate的批量查询条件
find(String) throws HibernateException;
find(String, Object, Type) throws HibernateException;
find(String, Object[], Type[]) throws HibernateException;
iterate(String)
iterate(String, Object, Type)
iterate(String, Object[], Type[])
其中的字符串参数表示一个可带查询参数的HQL查询字符串, 其中的每个 ? 代表一个参数, 而对应的Object[]参数表示每个?的值, 而Type[]数组代表每个参数的数值类型. 取自net.sf.hibernate.type.Type类的实现. net.sf.hibernate.type包下面有很多XXXType的实现类, 也可以使用net.sf.hibernate.Hibernate类的NullableType类型静态常量属性(表示Type类型的一个实现. 比如Hibernate.STRING表示一个字符串类型).
AddUserForm inData = (AddUserForm) form;
hsql =" From webapp.hibernate.pojo.UserPoJo As user2 Where user2.tel=? and user2.user=?";
s.find(hsql,new Object[]{inData.getTel(), inData.getUser()},
new Type[]{new net.sf.hibernate.type.StringType(), new net.sf.hibernate.type.StringType()});
/* //或者:
s.find( hsql,
new Object[]{ inData.getTel(), inData.getUser() } ,
new Type[]{ Hibernate. STRING, Hibernate.STRING } );
*/