Hibernate一级缓存与对象之间的关系

原文:https://www.cnblogs.com/cyxdn/p/8047862.html

Hibernate的一级缓存

  Hibernate的一级缓存是指Session缓存,Session缓存时一块内存空间,用来存放相互管理的Java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中,Hibernate一级缓存的作用就是减少对数据库的访问次数。

 

Hibernate的一级缓存会有如下特点:

  • 当应用程序调用Session接口的save() update() saveOrUpdate()  load()  get()方法以及以及Query接口的list() iterator()方法时,如果session缓存中没有相应的对象,Hibernate就会自动的把从数据库中查询到的相应对象信息加入到一级缓存中。
  • 当调用Session的close()方法时,Session缓存会被清空。

示例代码:

public class Demo1 {
    @Test
    public void func1(){
        Configuration configure=new Configuration().configure();
        SessionFactory sf=configure.buildSessionFactory();
        Session session=sf.openSession();
        Transaction transaction=session.beginTransaction();
        Customer c1= (Customer) session.get(Customer.class,"4028e48d604887ef01604887f2450000");
        Customer c2= (Customer) session.get(Customer.class,"4028e48d604887ef01604887f2450000");
        Customer c3= (Customer) session.get(Customer.class,"4028e48d604887ef01604887f2450000");
        transaction.commit();
        session.close();
        sf.close();
    }
}

应用程序打印输出结果:只会打印一次select语句。

Hibernate: 
    select
        customer0_.cust_id as cust1_0_0_,
        customer0_.cust_name as cust2_0_0_,
        customer0_.cust_source as cust3_0_0_,
        customer0_.cust_industry as cust4_0_0_,
        customer0_.cust_level as cust5_0_0_,
        customer0_.cust_linkman as cust6_0_0_,
        customer0_.cust_phone as cust7_0_0_,
        customer0_.cust_mobile as cust8_0_0_ 
    from
        CUST customer0_ 
    where
        customer0_.cust_id=?

缓存原理

  1. Java程序调用get查询缓存,先从缓存中查看是否存在查询的OID的对象,如果有,则直接返回到缓存中。
  2. 如果没有则发送sql语句到数据库进行查询
  3. 数据库将查询到的内容封装到ResultSet中返回。
  4. 将resultSet中的内容组装程查询的对象
  5. 将查询到的对象存入session缓存
  6. 将对象返回程序

 

 Hibernate缓存之快照

  1. Java程序调用get查询缓存,先从缓存中查看是否存在查询的OID的对象,如果有,则直接返回到缓存中。
  2. 如果没有则发送sql语句到数据库进行查询
  3. 数据库将查询到的内容封装到ResultSet中返回。
  4. 将resultSet中的内容组装程查询的对象,注意这里是组装成了两个对象,
  5. 将组装好的对象一个放入缓存中,一个放入快照中。
  6. 将缓存对象返回给程序
  7. 程序对返回的缓存对象进行修改
  8. 事物提交
  9. hibernate比对缓存中的对象和快照,如果有变化会同步到数据库中,如果没有变化则对数据库中的数据不做修改。

示例:当缓存对象与快照不一致时:

public class Demo1 {
    @Test
    public void func1(){
        Configuration configure=new Configuration().configure();
        SessionFactory sf=configure.buildSessionFactory();
        Session session=sf.openSession();
        Transaction transaction=session.beginTransaction();
        Customer c1= (Customer) session.get(Customer.class,"4028e48d604887ef01604887f2450000");
        c1.setCust_name("zhangsan");
        transaction.commit();
        session.close();
        sf.close();
    }
}

 程序打印输出为

Hibernate: 
    select
        customer0_.cust_id as cust1_0_0_,
        customer0_.cust_name as cust2_0_0_,
        customer0_.cust_source as cust3_0_0_,
        customer0_.cust_industry as cust4_0_0_,
        customer0_.cust_level as cust5_0_0_,
        customer0_.cust_linkman as cust6_0_0_,
        customer0_.cust_phone as cust7_0_0_,
        customer0_.cust_mobile as cust8_0_0_ 
    from
        CUST customer0_ 
    where
        customer0_.cust_id=?
Hibernate: 
    update
        CUST 
    set
        cust_name=?,
        cust_source=?,
        cust_industry=?,
        cust_level=?,
        cust_linkman=?,
        cust_phone=?,
        cust_mobile=? 
    where
        cust_id=?

当修改之后的缓存对象与数据库中的数据一致时:

public class Demo1 {
    @Test
    public void func1(){
        Configuration configure=new Configuration().configure();
        SessionFactory sf=configure.buildSessionFactory();
        Session session=sf.openSession();
        Transaction transaction=session.beginTransaction();
        Customer c1= (Customer) session.get(Customer.class,"4028e48d604887ef01604887f2450000");
        c1.setCust_name("zhangsan");
        c1.setCust_name("Zah");
        transaction.commit();
        session.close();
        sf.close();
    }
}

即将数据库中的数据先改为“zhangsan”,又改为原来的值时,发现程序打印输出的结果并没有执行update语句。

Hibernate: 
    select
        customer0_.cust_id as cust1_0_0_,
        customer0_.cust_name as cust2_0_0_,
        customer0_.cust_source as cust3_0_0_,
        customer0_.cust_industry as cust4_0_0_,
        customer0_.cust_level as cust5_0_0_,
        customer0_.cust_linkman as cust6_0_0_,
        customer0_.cust_phone as cust7_0_0_,
        customer0_.cust_mobile as cust8_0_0_ 
    from
        CUST customer0_ 
    where
        customer0_.cust_id=?

 所以hibernate提高效率有两种手段:1.使用缓存,减少不必要的查询;2.使用快照,减少不必要的更新操作。

 

Session一级缓存和对象状态之间的关系:

之前提到过的与session有关联,即为该对象存储在session缓存中,所以:

  • 瞬时态:没有id,没有存储在session缓存中
  • 持久态:有id,存储在session缓存中,只有持久态才会有一级缓存的概念
  • 脱管态(游离态):有id,没有存储在session缓存中
public class Demo1 {
    @Test
    public void func1(){
        Configuration configure=new Configuration().configure();
        SessionFactory sf=configure.buildSessionFactory();
        Session session=sf.openSession();
        Transaction transaction=session.beginTransaction();
        Customer c=new Customer(); //瞬时状态
        c.setCust_id("4028e48d604887ef01604887f2450000");//设置id,由新建状态转换为脱管状态
        session.update(c);//将对象放入session缓存中,持久化状态
        Customer c1= (Customer) session.get(Customer.class,"4028e48d604887ef01604887f2450000");//从缓存中取对象,持久化状态
        transaction.commit();//快照和缓存进行对比,如果不一致则提交数据库
        session.close();
        sf.close();
    }
}

 打断点测试只有在事务提交的时候,才会打印update语句。

下图来源:黑马程序员

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值