• Hibernate一级缓存详解


    一级缓存
    Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用get(),save(),update(),saveorupdate()等方法如session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中,--Hibernate一级缓存缓存的是对象, 注意查询接口Query下的list(),filter(),iterate()时,一级缓存是不起效果的。

     1 package com.oracle.dao;
     2 
     3 import java.util.List;
     4 
     5 import org.hibernate.Query;
     6 import org.hibernate.Session;
     7 import org.hibernate.SessionFactory;
     8 import org.hibernate.cfg.Configuration;
     9 import org.hibernate.stat.SessionStatistics;
    10 
    11 import com.oracle.dto.Student;
    12 
    13 /*
    14  * 测试Hibernate一级缓存
    15  */
    16 public class TestYiJiCache {
    17     Configuration config = new Configuration().configure();
    18     SessionFactory factory = config.buildSessionFactory();
    19     Session session = factory.openSession();
    20     
    21     public void sessionCache(){//一级缓存
    22         Configuration config = new Configuration().configure();
    23         SessionFactory factory = config.buildSessionFactory();
    24         Session session = factory.openSession();
    25 
    26         /*
    27         System.out.println("get之前的session:"+session);
    28         Student stu1 =(Student)session.get(Student.class, 2);//第一次查询,会输出查询语句
    29         System.out.println("get之后的session:"+session);
    30         Student stu2 =(Student)session.get(Student.class, 2);//第2次查询,同一个session下面不会输出查询语句了
    31         System.out.println("再get多一次的session:"+session);
    32         //再开启另外一个session,
    33         Session session2 = factory.openSession();
    34         Student stu3 =(Student)session2.get(Student.class, 2);//不同session下,一级缓存就失效了,会再次输出查询语句了
    35         
    36         session.beginTransaction().commit();
    37         session2.beginTransaction().commit();
    38         session.close();
    39         session2.close();*/
    40         
    41         Query query = session.createQuery("from Student");
    42         List<Student> list = query.list();//第一次查询,会输出查询语句
    43         
    44         System.out.println("===============看看是否开会输出查询上面相同的语句?====================");
    45         List<Student> list2 = query.list();//第2次查询,还是用样会输出查询语句了
    46         session.beginTransaction().commit();
    47         session.close();
    48         
    49         
    50         
    51     }
    52 }


    当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的记录,)

     1 Session session =SessionFactory.openSession();
     2 Transaction tx =session.beginTransaction();
     3 Itertaor users=session.find("from User u where u.age>0").itertaor();//HSL语句就不做解释了
     4 while(user.hasNext()){
     5 User user =(User)users.next();
     6 user.setAge(user.getAge()+1);
     7 //将本批插入的对象立即写入数据库并释放内存
     8 session.flush();
     9 session.clear();
    10 }
    11 tx.commit();
    12 session.close();
    View Code

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

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

    我们改一下上面的代码:

    虽说这是通过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();   注意.开源的MySQL中不支持存储过程的..


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

  • 相关阅读:
    ScriptOJ-flatten2#91
    ScriptOJ-unique#89
    ScriptOJ-safeGet#99
    测试
    SQL中常用的时间格式
    SQL Server -ISNULL()函数
    SQL Server -查看数据库扩展属性
    SQL Server 中创建数据库、更改主文件组示例
    SQL Server -SET QUOTED_IDENTIFIER
    SQL Server -SET ANSI_NULLS
  • 原文地址:https://www.cnblogs.com/sunliqing/p/3446346.html
Copyright © 2020-2023  润新知