zoukankan      html  css  js  c++  java
  • Hibernate一级缓存Session和对象的状态

    建议看原文:https://blog.csdn.net/qq_42402854/article/details/81461496

    一、session简介
            首先,SessionFactory 是线程安全的,SessionFactory 用到了工厂模式。

    session接口:

    Session 接口负责执行被持久化对象的CRUD操作。  Session 接口是一个非线程安全的,避免多个线程共享一个Session实例。

    Session 被称为持久化管理器。Session对象是Hibernate技术的核心,持久化化对象的生命周期、事务的管理和持久化对象的查询、更新和删除都是通过Session对象来完成的。

    Session 是一个轻量级对象。通常将每一个Session实例和一个数据库事务绑定。每执行一个数据库事务,不论执行成功与否,最后都因该调用Session的 Close() 方法,关闭Session释放占用的资源。

    session作用:

            1)减少访问数据库的频率

            2)保证缓存中的对象与数据库中的相关记录数据保持同步

    session清理缓存的时机

    清空缓存
            当调用 session.evict(customer); 或者session.clear(); 或者session.close()方法时,Session的缓存被清空。

    清理缓存
         Session具有一个缓存,又叫 Hibernate 的一级缓存,位于缓存中的对象处于持久化状态,它和数据库中的相关记录对应,Session能够在某些时间点,按照缓存中持久化对象的属性变化来同步更新数据库,这一过程被称为清理缓存。

    在默认情况下,Session会在下面的时间点清理缓存。

    当应用程序调用org.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存,然后在向数据库提交事务;

    当应用程序调用Session的list()或者iterate()时(【注】get()和load()方法不行),如果缓存中持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能能反映持久化对象的最新状态;

    当应用程序显式调用Session的flush()方法的时候

    在Session清理缓存的时候,会自动进行脏检查,如果发现Session缓存中的对象和数据库记录不一致,就会根据对象的最新属性去同步更新数据库。

    Hibernate5 清理缓存的模式不止三种

    Junit测试类:

    SessionFactory sessionFactory = null;
    Session session = null;
    Transaction transaction = null;

    @Before
    public void init() {
    // 1. 创建一个 SessionFactory 工厂类: 通过它建立一个与数据库连接回话 session
    // 配置类: 封装有我们的配置文件里的配置信息, 返回的 configuration 包含有配置文件里的具体信息
    Configuration configuration = new Configuration().configure();
    // Hibernate5规定: 所有配置或服务要生效, 必须将其注册到一个服务注册类中
    StandardServiceRegistry serviceRegistry = configuration.getStandardServiceRegistryBuilder().build();
    sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
    // 2. 通过工厂类开启 Session 对象
    session = sessionFactory.openSession();
    // 3. 开启事务
    transaction = session.beginTransaction();
    }

    @After
    public void destory() {
    // 5. 提交事务
    transaction.commit();
    // 6. 关闭 Session
    session.close();
    // 7. 关闭工厂类
    sessionFactory.close();
    }
    1. get方法 load方法
    @Test
    public void testGet() {
    //get方法/load方法: 通过id,获取数据中对应记录数据,返回对象,放到 session 的缓存中
    Student student = session.get(Student.class, 1); //发起sql查询语句
    student = null;
    Student student2 = session.get(Student.class, 1); //没有发起sql, 而是从缓存中获取数据
    System.out.println(student);
    System.out.println(student2);
    }
    结论:  session作用一证实

    get() 方法与 load() 方法区别

     1. get 是立即索引, load 是延迟索引

              执行 get() 方法:会立即加载对象

              执行 load() 方法: 若不使用该对象,则不会立即执行查询操作,而是生成一个代理对象,        

      2. load() 方法可能会抛出 LazyInitializationException异常:在需要初始化代理对象之前已经关闭了session.

      3. 若数据表中没有对应id 记录, session 也没有关闭

                get方法 返回 null

                load 方法:若不使用该对象的任何属性,没问题;若需要初始化,则抛出ObjectNotFoundException异常

    2. flush方法与reflush方法
    @Test
    public void testFlush() {
    Student student = session.get(Student.class, 1); //发起sql查询语句
    student.setName("张三"); // 该student对象处理后,放进session缓存中

    // 此时,session缓存中的student对象数据,和数据库中的数据不一致。
    //session.flush();//判断,一致:不会发起sql, 不一致: 发起一条update语句,但是不会提交事务, 可省略不写
    //transaction.commit(); // 真正提交事务之前(且只会)针对于持久对象,自动调用一次flush方法判断。
    }
     

    @Test
    public void testReflush() {
    Student student = session.get(Student.class, 1); //发起sql查询语句
    student.setName("李四"); //修改缓存中的数据
    System.out.println(student);

    // 此时,session缓存中的student对象数据,和数据库中的数据不一致。
    session.refresh(student);//不判断是否一致:都会发起sql,在判断缓存中的对象数据和数据库中非数据,一致: 不动作, 不一致,一条update语句,修改缓存中的数据与数据库数据一致,数据库记录没变化
    System.out.println(student);
    }
     结论: session作用二证实

    flush() 方法与 reflush() 方法区别:

            flush() 方法: 强制让session缓存中的数据与数据库中的记录数据保持一致,

                                   若不一致,则发起update语句修改数据库数据让其一致。

                a. flush() 可能会发送sql语句,但不会提交事务
                b. 在事务commit()提交之前先自动调用session的flush()方法,然后提交事务。


           reflush() 方法:强制发送一条select语句,保证让数据库中的记录数据与session缓存中的数据保持一致,

                                    若不一致,会修改session缓存中的数据让其一致

    3. clear() 方法 : 清空session缓存中的数据
    @Test
    public void testClear() {
    Student student = session.get(Student.class, 1); //发起sql查询语句
    System.out.println(student);
    session.clear(); //清空session中的数据
    //缓存中中不到id=1的student对象数据,重新发起sqlsql查询语句
    Student student2 = session.get(Student.class, 1);
    System.out.println(student2);
    }
     
    二、对象的主要三种状态:  
           

    1. 临时 / 瞬态状态(transient):OID 通常为 null

            没有session与其关联,数据库中也没有数据与之对应,一般是new出来的对象.超过作用域会被 JVM 垃圾回收器回收.

    @Test
    public void test1() {
    //student是Hibernate将要处理的对象,刚new出来,此时对象处于临时(瞬态)状态,即student为临时对象
    Student student = new Student("王五","男",new Date());

    //把临时对象放到session缓存中,并发起insert语句(在事务提交时才真正插入到数据库),此时临时对象转为持久状态,即student为持久对象:
    session.save(student);
    /*持久对象特征:
    * 1. 该对象被session托管,在session的缓存中要存在该对象
    * 2. 该对象的数据要在数据库的记录中有与之对应(对象OID和数据库记录id)的数据记录,这个Hibernate会拿到数据记录对象的id,即OID
    */
    transaction.commit();
    }
     

    2、持久状态(persistent): OID 不为 null 

               有相关联的session,并且相关联的session没有关闭,事务没有提交。数据库中也有数据与之对应.持久态对象发生改变,

               数据库中相关联的对象也会跟着改变.在事务提交时会影响到数据库,hibernate能够检测得到它的改变。

    @Test
    public void test1() {
    //student为临时对象
    Student student = new Student("王五","男",new Date());

    session.save(student); //student为持久对象
    student.setName("zs");
    transaction.commit(); // flush 会判断
    }
     

    @Test
    public void test() {
    //student为持久对象
    Student student = session.get(Student.class, 1);
    student.setName("zs");
    transaction.commit(); //(且只会)针对于持久对象,自动调用一次flush方法判断。
    }
     

    @Test
    public void test() {
    //student为持久对象
    Student student = session.load(Student.class, 1);
    student.setName("lisi");
    session.clear();
    transaction.commit(); //不动作, 无update语句。
    }
     

    3、游离 / 脱管状态(detached):  OID 不为 null ,不在 session 缓存中。

                 数据库中有数据与之对应,但没有 session 与其关联,脱管态的对象发生改变,hibernate 是检测不到的。

      1)save() 方法与 update() 方法

           Hibernate规定:  持久状态对象的id值不准修改,临时状态对象的id可以修改,游离状态对象的id可以被修改,但是没任何效果,,Hibernate会按照自己的机制,重构 id.

    @Test
    public void test() {
    //临时对象
    Student student = new Student("李四","男",new Date());
    //游离对象: student有id,但是这个对象是new出来的,没有被session托管,即没在session缓存里。
    student.setId(1); //id=1;数据库中有id=1的记录
    //studet从游离状态转为持久状态
    //session.save(student); //对游离状态的对象,设置的id无效, Hibernate会按照自己的机制发起insert语句,插入id值.

    //studet从游离状态转为持久状态
    //update作用: 更新,将处理的对象,先放到session缓存中,然后做更新数据库中对应id的记录值(无对应id报错)
    session.update(student);
    //student.setId(2); //再次修改id 提交报错, Hibernate规定 持久状态对象的id值不准修改,临时状态对象的id可以修改
    transaction.commit();
    }
     

    2)delete() 方法作用:把student对象从session缓存中删除,然后删除数据库对应id的记录

    @Test
    public void test3() {
    //临时对象
    Student student = new Student("李四","男",new Date());
    //游离对象
    student.setId(1); //id=1;数据库中有id=1的记录

    //studet从游离状态转为临时状态, 同时数据库对应id的记录会被删除,发起delete语句。
    session.delete(student);
    //delete方法作用:把student对象从session缓存中删除,然后删除数据库对应id的记录

    transaction.commit();
    }
    3)saveOrUpdate() 方法

    saveOrUpdate方法作用:save方法和update的综合体,
           如果student对象为临时状态: 调用save方法
           如果student对象为游离状态: 调用update方法

    @Test
    public void test4() {
    //临时对象
    Student student = new Student("admin","男",new Date());
    Student student2 = new Student("admin","女",new Date());
    //游离对象
    student.setId(2); //id=2;数据库中有id=2的记录

    session.saveOrUpdate(student); //调用update方法
    session.saveOrUpdate(student2); //调用save方法
    transaction.commit();
    }
    4)update() 方法

          Hibernate 不允许session缓存中有两个或两个以上相同 ID 值的对象存在。

    @Test
    public void test5() {
    //student持久对象
    Student student = session.get(Student.class, 2);

    //student2临时对象
    Student student2 = new Student();
    //student2游离对象
    student2.setId(2); //id=2;数据库中有id=2的记录

    session.update(student2); //update:将student2对象放进缓存时,报错NonUniqueObjectException

    transaction.commit();
    }
     

    三、Hibernate 拿到 jdbc 原生的 connection
    doWork() 方法: jdbc 操作 存储过程,批量操作。

    import org.hibernate.jdbc.Work;

    @Test
    public void test() {
    session.doWork(new Work() {
    public void execute(Connection arg0) throws SQLException {
    System.out.println(arg0); //com.mysql.jdbc.JDBC4Connection@30b34287
    }
    });
    }

  • 相关阅读:
    一个自动打补丁的脱机程序
    OPC 学习交流感想
    串口标准,说说流控制(RTS/CTS/DTR/DSR 你都明白了吗?)
    asp.net中调用COM组件发布IIS时常见错误 80070005解决方案
    可运行XP的最少后台服务配置
    MapGIS 7.0 SP2 企业版 & MapGIS 7.1IMS
    简单认识一下S60系统
    常用正则表达式
    图像处理:遮罩
    office2003中WORD中visio图无法打印中文问题解决方法
  • 原文地址:https://www.cnblogs.com/zhaoyanhaoBlog/p/11382449.html
Copyright © 2011-2022 走看看