Spring 事務中無法查到新增的資料原因
阿新 • • 發佈:2018-12-23
現象情況
資料庫: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);
}