Hibernate一级缓存详解及优化

1.Session 级别的缓存,它同session邦定。它的生命周期和session相同。Session消毁,它也同时消毁;管理一级缓存,一级缓存无法取消,用两个方法管理,clear(),evict()
2.两个session 不能共享一级缓存,因它会伴随session的生命周期的创建和消毁;
3.Session缓存是实体级别的缓存 ,就是只有在查询对象级别的时候才使用 ,如果使用HQL和SQL是查询属性级别 的,是不使用一级缓存的!切记!!!!
4.iterate 查询使用缓存,会发出查询Id的SQL和HQL语句,但不会发出查实体的,它查询完会把相应的实体放到缓存里边,一些实体查询如果缓存里边有,就从缓存中查询,但还是会发出查询id的SQL和HQL语句。如果缓存中没有它会数据库中查询,然后将查询到的实体一个一个放到缓存中去,所以会有N+1问题出现。

  每一个Hibernate Session实例和一个数据库事务绑定通常将每一个Hibernate Session实例和一个数据处理库事务绑定就是说,每执行一个数据库事务(操作),都应该先创建一个新的Hibernate Session实例.
如果事务执行中出现异常,应该撤消事务.不论事务执行成功与否,最后都应该调用Session的close()方法,从而释放Hibernate Session实例占用的资源.

  如何获得Session对象

首先创建SessionFactory对 象,如果访问多个数据源时,则应该产生多个SessionFactory;
  • 但是仅仅为了服务与某个请求时,不要创建一个新的SessionFactory,因为 创建SessionFactory需要消耗大量的资源 ,然后根据SessionFactory再创建Session对象
    Session session=factory.openSession();
        Transaction ts =   null ;
         try   {
          ts=session.beginTransaction();   //开始一个事务
          ...................                        //执行事务
          ts.commit();                            //提交事务
        }   catch   (HibernateException e) {       //如果出现异常就撤销事务
           if (ts!= null ){
            ts.rollback();                         //回滚事务
          }
          e.printStackTrace();
        }   finally {
          session.close(); //不管事务执行成功与否,最后都关闭Session并且放在finally中以提高安全性
        }
    下面我们重点看一下Session级的缓存
    Hibernate 缓存分为二级,第一级存放于 session 中称为一级缓存,默认带有且不能卸载
    因为 Session 的生命期往往很短,存在于 Session 内部的最快缓存的生命期当然也很短, 所以第一级缓存的命中率是很低的 。其对系统性能的改善也是很有限的。当然,这 Session 内部缓存的主要作用是保持 Session 内部数据状态同步 。并非是 hibernate 为了大幅提高系统性能所提供的。
    为了提高使用 hibernate 的性能,除了常规的一些需要注意的方法比如: 使用延迟加载、迫切外连接、查询过滤等以外,还需要配置 hibernate 的二级缓存。其对系统整体性能的改善往往具有立竿见影的效果。.
    应用
    Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用save(),update(),saveorupdate()等方法 及调用查询接口list,filter,iterate时,如session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中
    当Session关闭的时候该Session所管理的一级缓存也会立即被清除
    Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置

    一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储 的,在访问的时候使用的是主关键字ID
    虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。Session中所提供的干预方法包括以下两种
    ●evict() :用于将某个对象从Session的一级缓存中清除
    evict()方法适用于以下二种情况:
    1)不需要该对象进行同步的数据更新
    2)在批量进行更新与删除时,当更新删除每一个对象后,要释对此对象所占用的内存.

    ●clear() :用于将一级缓存中的所有对象全部清除。

    在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。
    Hibernate大批量更新时缓存的处理方法:
    (假设我们user表的age有5000条大于0的记录,)
    Session session =SessionFactory.openSession();
    Transaction   tx =session.beginTransaction();
    Itertaor users=session.find(" from   User   u   where   u.age>0").itertaor();//HSL语句就不做解释了
    while ( user .hasNext()){
    User   user   =( User )users.next();
    user .setAge( user .getAge()+1);
    //将本批插入的对象立即写入数据库并释放内存
    session.flush();
    session.clear();
    }
    tx. commit ();
    session. close ();

    用Hibernate处理大批数据时..都必须先执行5000次的update语句,然后才能更新5000个user 对象..
    这样就影响到了操作上的性能....在项目当我们遇到性能与空间的问题时,,,要以性能为主..这也就是说要牺牲空间

    所以程序最好跳过Hibernate API  而直接通过JDBC API来执来...

    我们改一下上面的代码:
    Session session=SessionFactory.openSession();
    Transaction   tx =session.beginTransaction();
    Connection conn =session.connection();
    PreparedStatement    pstmt = conn.prepareStatement(" update   users   set   age=age+1 "+" where   age >0");
    pstmt.executeUpdate();
    tx. commit ();

    虽说这是通过JDBC API.但本质上还是通过Hibernater Transaction的事务这个接口来声明事务的边界的...

    其实最好的解决方法就是以创建存储过程,,用底层的数据库运行..这样性能好,速度快....

    我就简单的以Oracle数据库为例子.创建一个名为UserUpdate的存储过程...然后在程序中进行调用...
        
    UserUpdate的存储过程代码:
                                                 create   or      replace   procadure UserUpdate(u_age   in   number)   as  
                                                 begin
                                                                           update   users   set   age=age+1   where   age>u_age;
                                                     end ;    
      
      下面的是在程序中如何调用我们命名的存储过程 
                         
    Session session =SessionFactory.openSession();
                                             Transaction tx =session.beginTransaction();
                                             Connection conn=session.connection();
                                         String str= "{call UserUpdate(?)}" ;
                                         CallableStatement cstmt= conn.prepareCall(str);
                                         cstmt.setInt(1,0);
                                        cstmt.executeUpdate();
                                        tx.commit();

    用JDBC API的好处是这样的..
    它不用把大批量的数据事先加载到内存中,然后再进行更新与修改..所以不会消耗大量内存....
    (小程序中是看不出什么差别的..当数据的记录达到一定的数据量的时候自然会发现用Hibernate API 与JDBC API的差别)
    在一个就是只能一条记录进行批量更新..不像Hibernate中更新每一条的..

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值