美文网首页技术分享
mybatis一级缓存对spring事务隔离级别表现的影响

mybatis一级缓存对spring事务隔离级别表现的影响

作者: 王帅199207 | 来源:发表于2019-12-18 11:22 被阅读0次

    先来看一个例子,我们先发起请求/testA,随后立即发起请求/testB:

        @Transactional
        @PostMapping("/testA")
        public void testA() throws InterruptedException {
            // 请求a  第一次查询  原值为100
            SellerCreditDO testDO = testMapper.findById(TEST_ID);
            System.out.println("request a ==> before change : " + testDO.getCreditScore());
    
            // sleep期间发起请求b
            Thread.sleep(5000L);
    
            // 请求a  第二次查询
            testDO = testMapper.findById(TEST_ID);
            System.out.println("request a ==> after change : " + testDO.getCreditScore());
        }
    
        @PostMapping("/testB")
        public void testB() {
            // 请求a第一次查询执行后发起请求b更新对应值值为90
            SellerCreditDO testDO = testMapper.findById(TEST_ID);
            testDO.setCreditScore(90);
            testMapper.update(testDO);
            System.out.println("request b => change value to 90 -----");
        }
    

    由于spring默认使用数据库的隔离级别,而阿里云rds默认使用的隔离级别为read committed,因此这里使用的是rc隔离级别,根据我们对隔离级别的认识,这里的输出应该为:

    request a ==> before change : 100
    request b => change value to 90 -----
    request a ==> after change : 90
    

    但是实际上,这里的输出为:

    request a ==> before change : 100
    request b => change value to 90 -----
    request a ==> after change : 100
    

    这里是否是因为spring使用的隔离级别不是read committed?我们来尝试做几个修改:


    • 我们将mybatis一级缓存的scope设置为statement(mybatis一级缓存默认开启,为session级别。):
    configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
    

    再次测试,我们发现得到了预期的输出:

    request a ==> before change : 100
    request b => change value to 90 -----
    request a ==> after change : 90
    

    • 不修改mybatis一级缓存的scope,去掉testA方法上的@Transaction注解

    再次测试,发现也能得到预期的输出。


    有了上面的案例,经过分析框架代码可以总结如下:

    1. mybatis一级缓存默认开启,是sqlSession级别的缓存,在同一个sqlSession下,对相同条件的sql查询结果会进行缓存。
    2. sqlSession调用flush或者close之后,会清理mybatis一级缓存;
      session内发生 insert、update 和 delete 操作时,会清空缓存;
      一个session内发生的insert、update 和 delete 操作,不会影响其他session内的一级缓存。
    3. 在spring集成mybatis时,如果不开启事务,spring对于每次查询会使用不同的sqlSession,因此mybatis一级缓存是不生效的(每次查询都是一个单独的事务);
      如果开启事务,spring在事务内会使用同一个sqlSession进行查询,这个时候mybatis一级缓存是生效的,而这个时候,在某些场景下我们只根据隔离级别作出的判断可能就不对了,需要注意。

    建议:一般不要使用mybatis提供的缓存,将一级缓存设置为statement级别。

    相关文章

      网友评论

        本文标题:mybatis一级缓存对spring事务隔离级别表现的影响

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