你好,我是miniluo,今天我和你聊聊Spring聲明式事務不生效的坑。java
下面就讓我和你一塊兒學習有哪些幾種狀況下Spring聲明式事務不生效的坑。ide
沒有正確理解@Transactional註解學習
你是否曾經寫過和下文相似的代碼?測試
@Service("productService")public class ProductServiceImpl implements IProductService {@Overridepublic void createProduct(Product product) {//此處可能會實現一些業務邏輯代碼,判斷是否知足建立產品的條件//請求內部方法建立產品 product.setProductName("Spring聲明式事務"); executeCreateProduct(product); }@Transactionalprivate void executeCreateProduct(Product product){if(Objects.isNull(product)){throw new RuntimeException("沒法建立空產品"); } product.create();//模擬出現異常期待事務回滾int zero = 1/0; }}
通過測試,咱們發現拋出了異常,但是產品仍是被建立了。緣由是,Spring 默認經過動態代理的方式實現 AOP,對目標方法進行加強,private 方法沒法代理到,這麼說咱們修改成public方法應該有效果。改完後再嘗試發現產品仍是被建立。這裏不得不說下@Transactional生效必須經過代理過的類從外部調用目標方法才能生效。知道這個緣由後,咱們把ProductServiceImpl以自身的方式注入,調整代碼以下:this
@Service("productService")public class ProductServiceImpl implements IProductService {@Autowiredprivate ProductServiceImpl self;@Overridepublic void createProduct(Product product) {//此處可能會實現一些業務邏輯代碼,判斷是否知足建立產品的條件 product.setProductName("Spring聲明式事務"); self.executeCreateProduct(product); //請求內部方法建立產品 }@Transactionalpublic void executeCreateProduct(Product product){if(Objects.isNull(product)){throw new RuntimeException("沒法建立空產品"); } product.create();int zero = 1/0; //模擬出現異常期待事務回滾 }}
再次測試,咱們發現產品並無被建立,說明事務已生效,由於self 是由 Spring 經過 CGLIB 方式加強過的類。這種方式雖然能解決,可是並不建議這麼作,而應該把@Transactional寫在接口的實現方法上,建議把查詢和更新(新增)分開。編碼
異常處理不當致使事務失效spa
狀況一:異常沒法從方法傳播出去,致使事務失效代理
@Service("productService")@Slf4jpublic class ProductServiceImpl implements IProductService {@Override@Transactionalpublic void createProduct(Product product) {//此處可能會實現一些業務邏輯代碼,判斷是否知足建立產品的條件 product.setProductName("Spring聲明式事務");try { executeCreateProduct(product); //請求內部方法建立產品 }catch (Exception ex){ log.error("建立產品失敗",ex); } }private void executeCreateProduct(Product product){if(Objects.isNull(product)){throw new RuntimeException("沒法建立空產品"); } product.create();int zero = 1/0; //模擬出現異常期待事務回滾 }}
這種寫法在實際編碼中常犯的錯誤,若要使其生效,只需在catch中增長code
TransactionAspectSupport.currentTransactionStatus() .setRollbackOnly();
狀況二:受檢異常致使事務不生效
接口
@Service("productService") @Slf4j public class ProductServiceImpl implements IProductService { @Override @Transactional public void createProduct(Product product) throws IOException { //此處可能會實現一些業務邏輯代碼,判斷是否知足建立產品的條件 product.setProductName("Spring聲明式事務"); executeCreateProduct(product); //請求內部方法建立產品 } private void executeCreateProduct(Product product) throws IOException { if(Objects.isNull(product)){ throw new RuntimeException("沒法建立空產品"); } product.create(); Files.readAllLines(Paths.get("transaction-not-rollback")); } }
或許有這麼個場景,這些代碼並不是你寫的,你並不知道外層或裏面的業務邏輯實現,改動可能會有影響存量功能;這個時候咱們該怎麼辦呢?其實也不難,@Transactional已經爲咱們給出瞭解決方案,只需將@Transactional調整爲
@Transactional(rollbackFor = Exception.class)
至此,我和你一塊兒回顧了平時編碼過程當中常見的坑,下面再一塊兒來看看關於事務傳播性的坑。
事務傳播性
咱們一塊兒來看下面的兩段代碼,第一段是實現建立產品和產品上架。
@Service("productService") @Slf4jpublic class ProductServiceImpl implements IProductService {@Autowiredprivate IOfferService offerService;/** * 指望:產品的建立並不會因上架失敗致使回滾 * @param product */@Override@Transactionalpublic void createProduct(Product product){//此處可能會實現一些業務邏輯代碼,判斷是否知足建立產品的條件 product.setProductName("Spring聲明式事務"); executeCreateProduct(product); //請求內部方法建立產品if(Status.UPSHELVE.equals(product.getStatus())){ offerService.productUpShelve(product);//建立產品後,產品隨即上架 } }private void executeCreateProduct(Product product) {if(Objects.isNull(product)){throw new RuntimeException("沒法建立空產品"); } product.create(); }}
第二段是產品上架的實現。
@Service("offerService")public class OfferServiceImpl implements IOfferService {@Override@Transactionalpublic void productUpShelve(Product product) { product.upShelve();throw new RuntimeException("上架失敗"); }}
咱們的指望是產品的建立成功與否不該該受到上架業務代碼影響,咱們測試後發現,產品上架失敗,致使建立產品回滾;這是什麼緣由呢?這是由於建立產品的事務和產品上架的事務是同一個事務,因此上架失敗天然會致使建立產品回滾。瞭解事務傳播性的同窗都知道,咱們只須要在產品上架的方法配置事務的傳播行爲便可,告訴@Transactional,我是要本身獨立事務
@Transactional(propagation = Propagation.REQUIRES_NEW)
好了,關於Spring聲明式事務常踩的3個坑已經和你一塊兒學習完,期待對你有所幫助和啓發。
思考和討論
一、文中咱們經過注入本身的方式解決了事務不生效的狀況,請問可否使用this來完成呢?this.executeCreateProduct(product);
二、說到事務的傳播行爲,除了我所說的以外,還有哪些呢?
歡迎留言與我分享和指正!也歡迎你把這篇文章分享給你的朋友或同事,一塊兒交流。
感謝您的閱讀,咱們下節再見!
關注咱們的公衆號,不定時分享技術、管理、業務等不一樣領域的文章與您一塊兒學習交流。也歡迎投稿:xiaouoron@foxmail.com