Spring 事务中无法查到新增的数据原因

现象情况

数据库:MySql
持久化框架:MyBatis
Srping 全局事务配置了两种:
1. 读写事务:使用了 PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
对应生效的方法如:insert* add* update* delete*等。
2. 只读事务:readOnly = true 使用了 PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
对应生效的方法如:除了读写事务和使用了注解@Transactional的方法之外的所有方法

模拟代码:

@Service
class ServiceA {
    @Autowired
    private UserMapper userMapper;

    //这个方法会使用事务的 PROPAGATION_NOT_SUPPORTED 特性
    public User getUserById(long id){
        return userMapper.getById(id);
    }
}

@Service
class ServiceB {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private ServiceA serviceA;

    //这个方法会使用事务的 PROPAGATION_REQUIRED 特性
    public void addUser(User user){
        userMapper.insert(user);
        System.out.println(user.getId()); //这里有打印出id,代表插入成功了
        user = serviceA.getUserById(user.getId());
        System.out.println(user);  //再去查询就返回的user是null,查询不到刚插入的数据了
        user.getId();  //再使用user,因为user是null,会报空指针异常,然后事务回滚了,user也没添加成功
    }
}

原因:

serviceA.getUserById(long) 方法使用了PROPAGATION_NOT_SUPPORTED,把原来serviceB.addUser(User) 的事务挂起来了,没在同一个事务中,同时因为 MySql 事务隔离级别默认为 READ_COMMITTED 一个事务提交后才能被其他事务读取到。因为 addUser 的事务还没提交,getUserById 又不在同一个事务中,由于事务的隔离性,所以 getUserById 就查询不到新增的数据。

解决方法:

把 serviceA.getUserById(long) 事务的隔离级别设为 READ_UNCOMMITTED 最低隔离级别、事务未提交前,就可被其他事务读取。这样就可以读取到其它事务的数据了,但这样有个坏处,会出现幻读、脏读、不可重复读。所以要根据业务场景来使用。

    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public User getUserById(long id){
        return userMapper.getById(id);
    }

你可能感兴趣的:(笔记,Mysql,spring-boot)