1. 程式人生 > >Spring 事務中無法查到新增的資料原因

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);
    }