现在的位置: 首页 > 综合 > 正文

Hibernate Session操作, 查询过滤, 缓存利用, 批量处理

2013年08月14日 ⁄ 综合 ⁄ 共 14605字 ⁄ 字号 评论关闭

1.   Session---单数据加载---load/ get

Load方法根据指定的实体类和id从数据库装载认为存在的一条记录. 应该确保对象确实存在, 否则会抛出ObjectNotFoundException.

Load方法可返回实体的代理类实例, 可充分利用内部缓存和二级缓存中的现有数据.

 

get方法根据指定的实体类和id从数据库查询并装载一条记录.数据不存在将得到null.

get方法返回的永远是实体类. 只在内部缓存中进行数据查找, 如果没有数据就调用SQL完成数据读取.

 

  1. 出于性能考虑,避免无谓的数据库访问,Session在调用数据库查询功能之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,如果第一级缓存查找命中,且数据状态合法,则直接返回。
  2. 之后,Session会在当前 “NonExists”记录中进行查找,如果 “NonExists”记录中存在同样的查询条件,则返回null。“NonExists”记录了当前 Session实例在之前所有查询操作中,未能查询到有效数据的查询条件。如果Session中一个无效的查询条件重复出现,即可迅速做出判断。
  3. 对于load方法而言,如果内部缓存中没有发现有效数据,则查询第二级缓存,如果第二级缓存命中,则返回。
  4. 如果在缓存中未发现有效数据,则发起数据库查询操作(Select SQL).
  5. 如果经过查询未发现对应记录,则将此次查询的信息在 “NonExists”中加以记录,并返回null。
  6. 否则根据映射配置和Select SQL得到的 ResultSet,创建对应的数据对象. 并将其数据对象纳入当前Session实体管理容器(一级缓存)。
  7. 执行Interceptor.onLoad方法(如果有对应的Intercepeor)。
  8. 将数据对象纳入二级缓存。
  9. 如果数据对象实现了LifeCycle接口,则调用数据对象的onLoad方法。
  10. 返回数据对象。

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只在特定的情况下产生作用:

  1. 完全相同的Select SQL重复执行。
  2. 再两次查询之间,此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 } );

 

*/

6.   Hibernate2/3的Criteria批量查询条件

抱歉!评论已关闭.