有時候,我們明明在類或者方法上添加了@Transactional註解,卻發現方法並沒有按事務處理。其實,以下場景會導致Spring的@Transactional事務失效。 1、事務方法所在的類沒有載入到Spring IOC容器中。 @Transactional是Spring的註解,未被Spring管 ...
有時候,我們明明在類或者方法上添加了@Transactional註解,卻發現方法並沒有按事務處理。其實,以下場景會導致Spring的@Transactional事務失效。
1、事務方法所在的類沒有載入到Spring IOC容器中。
@Transactional是Spring的註解,未被Spring管理的類中的方法不受@Transactional註解控制,這個應該很好理解。
2、方法沒有被public修飾。
眾所周知,java的訪問許可權修飾符有:private
、default
、protected
、public
四種,但是@Transactional
註解只能作用於public
修飾的方法上。具體為什麼會這樣,我也沒理解,就先記住吧。
3、在同一個類中的方法調用@Transactional方法。
假如在同一個類中有A、B兩個方法,如下:
@Service public class UserServiceImpl { @Autowired UserMapper userMapper; public void A() { B(); } @Transactional public void B() { userMapper.deleteById(1); int i = 10 / 0; //模擬發生異常 } }
像上面的代碼,B
方法使用@Transactional
註解標註,在A()
方法中調用了B()
方法,在外部調用A()
方法時,B()方法的事務不會生效。這是由於使用Spring AOP
代理造成的,因為只有當事務方法被當前類以外的代碼調用時,才會由Spring
生成的代理對象來管理。
4、方法的事務傳播類型不支持事務。
當@Transactional的propagation設置為NOT_SUPPORTED時,也就是@Transactional方法總是非事務方式執行。(Spring事務傳播行為可以查閱我之前的一篇文章:Spring事務(一)-事務傳播行為)
5、不正確地捕獲異常。
使用了try-catch代碼塊將異常捕捉了,沒有向上拋出異常,事務不會回滾。
6、標註錯誤的異常類型。
Spring事務預設回滾類型是RuntimeException類型,如果沒有制定回滾的類型,拋出的錯誤不是RuntimeException類型,則無法回滾。
7、資料庫不支持事務。
以MySQL為例,InnoDB引擎是支持事務的,而像MyISAM、MEMORY等是不支持事務的。 從MySQL5.5.5開始預設的存儲引擎是InnoDB,之前預設都是MyISAM。