@Transactional是一種基于注解管理事務的方式,spring通過動态代理的方式為目标方法實作事務管理的增強。
@Transactional使用起來友善,但也需要注意引起@Transactional失效的場景,本文總結了七種情況,下面進行逐一分析。這些場景無論是開發還是面試都能用得上,簡介明了,通俗易懂
1、異常被捕獲後沒有抛出
當異常被捕獲後,并且沒有再抛出,那麼deleteUserA是不會復原的。
@Transactional
public void deleteUser() {
userMapper.deleteUserA();
try {
int i = 1 / 0;
userMapper.deleteUserB();
} catch (Exception e) {
e.printStackTrace();
}
}
2、抛出非運作時異常
異步雖然抛出了,但是抛出的是非RuntimeException類型的異常,依舊不會生效。
@Transactional
public void deleteUser() throws MyException{
userMapper.deleteUserA();
try {
int i = 1 / 0;
userMapper.deleteUserB();
} catch (Exception e) {
throw new MyException();
}
}
如果指定了復原異常類型為Exception,那麼就可以復原非RuntimeException類型異常了。
@Transactional(rollbackFor = Exception.class)
3、方法内部直接調用
如果先調用deleteUser(),那麼deleteUserA()是不會復原的,其原因就是@Transactional根本沒生成代理,如果直接調用deleteUser2()那麼沒問題,deleteUserA()會復原。
public void deleteUser() throws MyException{
deleteUser2();
}
@Transactional
public void deleteUser2() throws MyException{
userMapper.deleteUserA();
int i = 1 / 0;
userMapper.deleteUserB();
}
修改方式,把目前類自己注入一下調用即可。
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
//自己注入自己
@Autowired
UserService userService;
public void deleteUser() throws MyException{
userService.deleteUser2();
}
@Transactional
public void deleteUser2() throws MyException{
userMapper.deleteUserA();
int i = 1 / 0;
userMapper.deleteUserB();
}
}
4、新開啟一個線程
如下的方式deleteUserA()也不會復原,因為spring實作事務的原理是通過ThreadLocal把資料庫連接配接綁定到目前線程中,新開啟一個線程擷取到的連接配接就不是同一個了。
@Transactional
public void deleteUser() throws MyException{
userMapper.deleteUserA();
try {
//休眠1秒,保證deleteUserA先執行
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
int i = 1/0;
userMapper.deleteUserB();
}).start();
}
5、注解到private方法上
idea直接會給出提示Methods annotated with ‘@Transactional’ must be overridable ,原理很簡單,private修飾的方式,spring無法生成動态代理。
@Transactional
private void deleteUser() throws MyException{
userMapper.deleteUserA();
int i = 1/0;
userMapper.deleteUserB();
}
6、資料庫本身不支援
mysql資料庫,必須設定資料庫引擎為InnoDB。
7、事務傳播屬性設定錯誤
注意傳播屬性的設定,比如設定了:PROPAGATION_NOT_SUPPORIED(以非事務的方式執行,如果目前有事務則把目前事務挂起)。
轉載來源|blog.csdn.net/CSDN_WYL2016/article/details/106767583