hibernate 一级缓存实践

    @Transactional
    public Tao testHibernateCache() {
        Tao tao = taoDao.findOne(1);
        tao.setCol2("new");
        tao = taoDao.findOne(1);
        return tao;
    }

输出:Hibernate: select tao0_.col1 as col1_60_0_, tao0_.col2 as col2_60_0_ from tao tao0_ where tao0_.col1=?

Hibernate: update tao set col2=? where col1=?

返回:new

加上事务注解后,几个mysql io session 为同一个,由于一级缓存,第3条findOne没有执行


********************************************

//    @Transactional
    public Tao testHibernateCache() {
        Tao tao = taoDao.findOne(1);
        tao.setCol2("new");
        tao = taoDao.findOne(1);
        return tao;
    }


输出:Hibernate: select tao0_.col1 as col1_60_0_, tao0_.col2 as col2_60_0_ from tao tao0_ where tao0_.col1=?

返回:new,也就是说第2次如果没有缓存,应该查询到old

这里比较奇怪的是,未加事务注解,从现象看,第2次查询没有执行,用的一级缓存,而

根据此前的博客资料:三次请求(读-改-读)引出nibernate 一级缓存:一级缓存是Session级别的缓存,它属于事务范围的缓存,事务结束时,缓存的生命周期也结束了;显然在这个地方,缓存没结束,是不是也意味着这两个查询是一个事务?还是说不同的事务,但是是一个session?


*****************************************

带着问题找到这篇文章

https://www.cnblogs.com/200911/archive/2012/10/09/2716873.html

hibernate缓存:一级缓存和二级缓存

这篇文章中,

Session缓存(又称作事务缓存):Hibernate内置的,不能卸除。

缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。

public class Client
{
    public static void main(String[] args)
    {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        try
        {
            /*开启一个事务*/
            tx = session.beginTransaction();
            /*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/
            Customer customer1 = (Customer)session.get(Customer.class, "402881e534fa5a440134fa5a45340002");
            System.out.println("customer.getUsername is"+customer1.getUsername());
            /*事务提交*/
            tx.commit();
            
            System.out.println("-------------------------------------");
            
            /*开启一个新事务*/
            tx = session.beginTransaction();
            /*从数据库中获取id="402881e534fa5a440134fa5a45340002"的Customer对象*/
            Customer customer2 = (Customer)session.get(Customer.class, "402881e534fa5a440134fa5a45340002");
            System.out.println("customer2.getUsername is"+customer2.getUsername());
            /*事务提交*/
            tx.commit();
            
            System.out.println("-------------------------------------");
            
            /*比较两个get()方法获取的对象是否是同一个对象*/
            System.out.println("customer1 == customer2 result is "+(customer1==customer2));
        }
        catch (Exception e)
        {
            if(tx!=null)
            {
                tx.rollback();
            }
        }
        finally
        {
            session.close();
        }
    }
}

其原理是在同一个Session里面第一次调用get()方法, Hibernate先检索缓存中是否有该查找对象,发现没有,Hibernate发送SELECT语句到数据库中取出相应的对象,然后将该对象放入缓存中,以便下次使用,第二次调用get()方法,Hibernate先检索缓存中是否有该查找对象,发现正好有该查找对象,就从缓存中取出来,不再去数据库中检索,没有再次发送select语句。

特点:一个session,两个事务

可以看到,代码用一个session开启了两个事务,同样使用了一级缓存,所以一级缓存应当与session挂钩,而不与事务挂钩

“一级缓存是Session级别的缓存,它属于事务范围的缓存,事务结束时,缓存的生命周期也结束了;”

改为:

“一级缓存是Session级别的缓存,它属于会话范围的缓存,会话结束时,缓存的生命周期也结束了;”

故引出:会话和事务的区别


再回到第二个例子中,

在spring-data-jpa 中,springboot 获取hibernate 的 SessionFactory (未完),对未➕事务注解的代码无效,所以只能猜测,同一个函数的请求,虽然没有  try commit catch rollback  操作,但复用了一个Connection,属于同一个会话,而一级缓存与会话挂钩,所以即使多个访问没有事务(或多个事务),也产生了缓存。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值