Hibernate学习笔记之持久层操作

来源:互联网 发布:怎样进行网络推广 编辑:程序博客网 时间:2024/04/30 14:45

数据加载

Session.get/load
这两个方法都是用来根据实体类以及id从数据库读取数据,并返回对于那个实体对象。
区别:

  1. 如果未能查询到符合条件的记录,get返回null,load抛出ObjectNotFoundException。
  2. load方法可以返回实体的代理类实例,而get方法只能返回实体类。
  3. load方法可以利用内部缓存和二级缓存的数据,而get方法只能利用内部缓存,如果在内部缓存中没有命中,直接执行sql完成查询。

Session加载实体对象的过程:

  1. Session在调用sql查询前会先在第一级缓存中根据实体类和id进行查找,如果命中则返回。
  2. 如果第一步没有找到,Session会在当前的“NonExists“记录中查找,如果存在相同的查询条件,则返回Null。“NonExists“记录了当前Session实例在之前所有查询操作中,未能查询到有效数据的查询条件。如果一个Session中无效的查询条件重复出现,即可迅速作出判断,减少对数据库的无效访问。
  3. 对load方法而言,如果内部缓存没有命中则会继续尝试二级缓存,如果二级缓存命中则返回。
  4. 如果在缓存中未查询到数据,则执行sql。如果为查询到数据,则将此次查询信息记录在”NonExists”记录中,并返回Null。
  5. 根据映射配置和ResultSet创建数据对象。
  6. 将数据对象纳入Session实体管理容器(内部缓存)。
  7. 执行Interceptor.onLoad方法。
  8. 将数据纳入二级缓存。
  9. 如果数据对象实现了LifeCycle接口,则调用 数据对象的onLoad方法。
  10. 返回数据对象。

Query.list/iterate
通过list或iterate方法可以完成数据批量查询,但是他们的机制是不同的。

list方法:

        Query query=session.createQuery("from Userbean user where user.id>0");        List<Userbean> list=query.list();        for (Userbean userbean : list) {            System.out.println(userbean.getLoginName());        }

运行结果:

Hibernate: select userbean0_.id as id0_, userbean0_.email as email0_, userbean0_.loginName as loginName0_, userbean0_.password as password0_ from userbean userbean0_ where userbean0_.id>0
yukjin
1

iterate方法:

        Iterator<Userbean> it=query.iterate();        while(it.hasNext()){            System.out.println(it.next().getLoginName());        }

运行结果:

Hibernate: select userbean0_.id as col_0_0_ from userbean userbean0_ where userbean0_.id>0
Hibernate: select userbean0_.id as id0_0_, userbean0_.email as email0_0_, userbean0_.loginName as loginName0_0_, userbean0_.password as password0_0_ from userbean userbean0_ where userbean0_.id=?
yukjin
Hibernate: select userbean0_.id as id0_0_, userbean0_.email as email0_0_, userbean0_.loginName as loginName0_0_, userbean0_.password as password0_0_ from userbean userbean0_ where userbean0_.id=?
1

通过运行结果可以看到,list方法执行了一条sql语句,而iterate方法执行了3条,第一条先查出Id,然后再根据id一个一个select出信息。看上去iterate方法会导致效率不高,但正是它的这种方式,使它可以利用Hibernate缓存。

如下代码连续执行两次查询:

        Query query=session.createQuery("from Userbean user where user.id>0");        List<Userbean> list=query.list();        for (Userbean userbean : list) {            System.out.println(userbean.getLoginName());        }        Iterator<Userbean> it=query.iterate();        while(it.hasNext()){            System.out.println(it.next().getLoginName());        }

结果:

Hibernate: select userbean0_.id as id0_, userbean0_.email as email0_, userbean0_.loginName as loginName0_, userbean0_.password as password0_ from userbean userbean0_ where userbean0_.id>0
yukjin
1
Hibernate: select userbean0_.id as col_0_0_ from userbean userbean0_ where userbean0_.id>0
yukjin
1

可以看到这次iterate方法只执行了一句sql从数据库查询出符合条件的id,然后直接根据Id从缓存中返回实体对象。

而list方法是无法利用缓存的(这里就不再实验),例如第一此查询的是id>0的,而第二次查询的是id>2的,list无法确保id>2的结果在缓存中有完整的数据集,只能再次执行sql查询结果。

延迟加载

userbean表和address表存在一对多的关系,address表中存在一个外键userbean_id来绑定一个userbean。反映在实体类则是Userbean类中有一个Set类型的属性address来存储该实体类关联的Address类,而Address有一个Userbean类型的属性关联所属的Address类。当我们通过前面提到的load或get方法加载Userbean时,Hibernate默认会把所关联的Address信息也加载进来,而倘若我们只需要的是登录名,那么无疑是加载了无用信息。延迟加载就是为了解决这样的问题,它会在真正需要address的时候才去加载。

        <set name="addresses" lazy="true" inverse="true" cascade="none">            <key>                <column name="userbean_id" />            </key>            <one-to-many class="bean.Address" />        </set>

通过设置lazy属性开启延迟加载。

批量删除

Hibernate2中的批量删除操作的实现是通过循环调用delete sql语句,因此会造成性能上的损耗,在Hibernate3中是通过一条删除语句实现的,但是却引来了新的问题,缓存与数据库数据不一致,例如以下代码:

        Userbean user=(Userbean) session.load(Userbean.class,new Integer(4));        System.out.println(user.getLoginName());        Transaction transaction=session.beginTransaction();        String hql="delete from Userbean u where u.id>3";        Query query=session.createQuery(hql);        query.executeUpdate();        transaction.commit();        user=(Userbean) session.load(Userbean.class,new Integer(4));        System.out.println(user.getLoginName());

运行结果:

Hibernate: select userbean0_.id as id0_0_, userbean0_.email as email0_0_, userbean0_.loginName as loginName0_0_, userbean0_.password as password0_0_ from userbean userbean0_ where userbean0_.id=?
3
Hibernate: delete from userbean where id>3
3

代码首先通过load方式加载id等于4的用户,然后通过批量删除操作将id>3的用户信息从数据库中删除,紧接着通过load方法重新加载id=4的用户。从运行结果中可以看到,第二次加载到了已经被删除的数据。

0 0
原创粉丝点击