美文网首页hibernate学习
3.一级缓存与快照机制

3.一级缓存与快照机制

作者: 棱锋 | 来源:发表于2019-11-10 20:30 被阅读0次

    一级缓存

    hibernate一级缓存即为session缓存,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。只要 Session 实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。

    session缓存特点

    1. 当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中去。

    2. 当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。

    3. 当调用Session的close()方法时,Session缓存会被清空。

    4. 也可以强制使用session.clear(),清空缓存

    数据同步问题

    当缓存中已有一个对象时,此时通过外部手段更新数据库中此条数据,再次使用此session.get()获取此条数据,就不会是更新后的数据

    测试

            Session session = HibernateUtil.openSession();
            Customer customer = session.get(Customer.class, 94L); //先查数据库,并将结果存在一级缓存中
            System.out.println(customer);
            customer.setCustName("Elijah");
            Thread.sleep(5000);
            //session.clear(); //clear方法会强制清空缓存
            Customer customer1 = session.get(Customer.class, 94L); //此处使用了一级缓存,没有直接查数据库,所以这边的name并不是数据库真实name
            System.out.println(customer1); //打印出name为Elijah
            System.out.println(customer == customer1); //结果为true
            session.close();//session关闭后一级缓存就随之关闭
    

    快照机制

    Hibernate 向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果两个对象中的属性发生变化,则自动执行update语句,将缓存的内容同步到数据库,并更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            Customer customer = session.get(Customer.class, 94L);
            System.out.println(customer.getCustName());
    
            customer.setCustName("Yang");
            System.out.println(customer.getCustName());
    
            // 未使用update, 但是此处却更新了数据库
            tx.commit();
            session.close();
    
            System.out.println(customer.getCustName());
    

    注意如果没有手动开启事务,使用了自动提交的话,是不会去更新数据库的.

    对象三种状态

    在Hibernate中持久化的对象可以划分为三种状态,分别是瞬时态、持久态和脱管态,一个持久化类的实例可能处于三种不同状态中的某一种

    1.瞬时态(transient)

    也称临时态,自由态,指直接使用构造方法创建的实例对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联

    2.持久态(persistent)

    持久态的对象存在持久化标识OID ,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的,即存入缓存时变成持久态

    3.托管态(detached)

    脱管态也称离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭时就变成了脱管态,或者构造方法创建实例时,指定了确实存在的id。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到

    代码说明

            Customer customer = new Customer();
            customer.setCustName("Yang");
            customer.setCustId(95L); //瞬时态transient
            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            session.save(customer); //持久状persistent, session缓存中已有
    
            System.out.println(customer.getCustId());
            Customer customer1 = session.get(Customer.class, customer.getCustId()); //不查数据库,只查了缓存
            System.out.println(customer1 == customer);
    
            tx.commit();
            session.close(); //托管态 detached
    

    状态转换图

    hibernate中对象的状态.png

    saveOrUpdate

    此方法比较特殊,当对象为临时态时执行save,当对象为托管态时执行update。

            Customer customer = new Customer();
            customer.setCustName("assss"); //瞬时态transient
            Session session = HibernateUtil.openSession();
            Transaction tx = session.beginTransaction();
            session.saveOrUpdate(customer); //由瞬时到持久态,save
            tx.commit();
            session.close();
    
            customer.setCustName("ssss");  //托管态
            Session session1 = HibernateUtil.openSession();
            Transaction tx1 = session1.beginTransaction();
            session1.saveOrUpdate(customer); //由托管到持久,update
            tx1.commit();
            session1.close();
    

    merge

    在正常情况下merge的功能同于saveOrUpdate。只有下列情况:

    Session session = HibernateUtil.openSession();
    Transaction tx = session.beginTransaction();
    Customer customer = session.get(Customer.class, 1L);  //持久态
    tx.commit();
    session.close();   //托管态
    
    Session session1 = HibernateUtil.openSession();
    Transaction tx1 = session1.beginTransaction();
    Customer customer1 = session1.get(Customer.class, 1L);
    customer.setCustName("黑马程序员顺义校区");
    //session1.update(customer);   //将托管态的customer转成持久态,此时出现问题,已经缓存存在一个持久态的customer1,且他们的属性值并不完全一样
    session1.merge(customer); //merge的作用就是用缓存外的merge缓存中的,来解决上述的矛盾
    tx1.commit();
    session1.close();
    System.out.println(customer1.getCustName()); //customer1的值发生改变
    

    customer在session关闭后处于游离态,因为session1重新从数据库中获取了一个对象customer1成持久态。

    update会让那个customer也变成持久态,两个持久态会冲突,报错:“A different object with the same identifier value was already associated with the session”

    然而用merge的话,它会把游离态的customer赋值给已经处于持久化的customer1中,自己本身不得变为持久态

    相关文章

      网友评论

        本文标题:3.一级缓存与快照机制

        本文链接:https://www.haomeiwen.com/subject/gzwlvctx.html