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

先来看一个例子,我们先发起请求/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级别。

推荐阅读更多精彩内容