spring事物隔离级别和mybatis缓存的问题

今天使用@Transactional遇到了问题,通过一些实验,总结下自己的想法。如有不当欢迎指正~

项目使用spring boot + mybatis + mysql,先上代码:

    @Override
    @Transactional
    public void test(){
        UDeptDO dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537");
        // 打印旧值
        log.info("deptname={}", dept.getDeptname());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }
        dept.setDeptname("test");
        update(dept);
        dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537");
        // 打印新值
        log.info("deptname={}", dept.getDeptname());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }
    }
    
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void test1(){  
        UDeptDO dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537");
        // 打印旧值
        log.info("deptname={}", dept.getDeptname());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }
        // 打印旧值,事物未提交
        dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537");
        log.info("deptname={}", dept.getDeptname());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
        }
        // 打印新值,事物已提交,READ_COMMITTED生效
        dept = uDeptDao.get("0cf58a5d6ae811e89feafa163eb3e537");
        log.info("deptname={}", dept.getDeptname());
    }

以上是一个service实现类的两个测试方法,方法test使用Spring事物的默认隔离级别(也就是由底层数据库提供的隔离级别,mysql默认是REPEATABLE_READ),方法test1使用READ_COMMITTED。同时调用test和test1,预期test1方法第三次查询能获取到修改值,但是并没有成功(此处纠结了好久,还以为自己理解错了。。。)。分析日志发现test1后两次查询未打印SQL语句,估计是缓存的原因。给mapper文件的查询语句加上useCache="false" flushCache="true"这两个配置,问题解决。

spring事物隔离级别和mybatis缓存的问题_第1张图片

从这个例子可以看到,READ_COMMITTED可以避免dirty reads,即test1第二次查询不会查到test的修改,只有test方法事物提交后,test1在第三次查询才能看到。这里test1方法后两次的查询行为,其实就是我们常说的non-repeatable reads。如果使用REPEATABLE_READ级别,能使test1的三次查询结果保持一致。

你可能感兴趣的:(spring事物隔离级别和mybatis缓存的问题)