Spring新增数据后立即查询,但是查询不到#Mybatis新增数据丢失

项目中遇到的问题, spring先新增了一条记录, 然后立即进行查询,但打死查询不到。

这里简单进行总结记录一下。

首先说可能的原因:

  1. 主从数据同步延迟导致
  2. 代码事务控制有问题
  3. 其他应用删除了目标数据

这里直接说结论, 我这边时事务的隔离级别有问题。

好了, 接下来复原一下当时的场景:

代码中会新增数据, 然后再进行查询; 代码示例如下:

    @Transactional(propagation = Propagation.REQUIRED)
    public PayedResult saveWithdrawOrder(Integer fastOrderNo) {
                // 先插入数据, 插入后使用数据库工具进行查询可以查询到数据
                methodA();
                // 根据ID获取数据, 这里打死获取不到
                getById();
    }

   @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public PayedResult methodA(Integer fastOrderNo) {
         // 这里是新增数据代码
    }


   @Transactional(propagation = Propagation.REQUIRES, rollbackFor = Exception.class)
    public PayedResult getById(Integer fastOrderNo) {
      // 这里根据ID进行查询, 此时使用数据库工具可以查询到新增的数据
         
    }

代码大概就像上面的, 但是死活拿不到数据。 然后新增一个线程可以获取到数据。

因为新增使用的传播机制是 requires_new, 所以肯定是数据已经提交。

此时要注意的是数据隔离级别。 默认是 

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)

此种注解, 隔离级别是使用的数据库默认的。 

然后就去查一下数据库隔离级别, 

select @@global.tx_isolation;

特么的居然是

Spring新增数据后立即查询,但是查询不到#Mybatis新增数据丢失_第1张图片

 此时就什么都明白了, 当前事务使用的是可重复读, 即:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。所以是肯定读取不到数据的。

另外也复习一下下隔离级别:

读未提交(READ UNCOMMITTED):一个事务还没提交时,它做的变更就能被别的事务看到。

读提交(READ COMMITTED):一个事务提交之后,它做的变更才会被其他事务看到。

可重复读(REPEATABLE READ):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。

串行化(SERIALIZABLE):对于同一行记录,“写”会加“写锁”,“读”会加“读锁”,当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

修改方案也简单了,将读取方法事务隔离级别修改为 read_commited; 修改如下即可:

 @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
    public PayedResult getById(Integer fastOrderNo) {
      // 这里根据ID进行查询, 此时使用数据库工具可以查询到新增的数据
         
    }

因为spring事务传播级别, 如果不新开事务, 那么也会继承父级的事务隔离级别。 所以这里必须使用 required_new;

你可能感兴趣的:(Springboot,spring,java,后端)