SpringBoot中@Transiactional註解沒有效果的解決
SpringBoot @Transiactional註解沒有效果
背景
數據庫為mysql
問題
使用SpringBoot操作數據庫插入兩條數據,service層的方法出現瞭異常,按理說兩條數據都該插不進去的,可以數據庫中卻還是有一條數據。
數據庫表格式:
service層代碼:
package com.example.demo.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.example.demo.domain.Girl; import com.example.demo.repository.GirlRepository; @Service public class GirlService { @Autowired private GirlRepository girlRepository; @Transactional public void transiactionTest() { Girl g1 = new Girl(); g1.setAge(33); g1.setCupSize("B"); girlRepository.save(g1); Girl g2 = new Girl(); g2.setAge(33); g2.setCupSize("FFFFF"); // 長度和數據庫的長度不符,會出異常 girlRepository.save(g2); } }
啟動SpringBoot後,訪問對應的方法,控制臺也報錯,但是表中是有一條數據的(原本是空表)。
查瞭查資料說的是在設計表的時候要選取的InnoDB引擎。
回頭看我的表引擎:
還真的是。。。。。。
解決
將數據表的引擎設置為InnoDB引擎。 然後再次執行,@Transitional註解才起瞭作用,數據表中沒有瞭數據。
SpringBoot 使用Transaction註解遇到的坑
一、場景
開發一個多批次入庫的功能,功能中涉及到多個表間的操作,對數據庫表的操作要麼同時成功,要麼同時失敗,不然就會存在臟數據,所以使用到瞭事務這個知識點()。
劃重點:重要的都使用紅色標出來瞭,大傢如果不想看我廢話,直接跳到紅色字體即可0…0
二、Spring中使用的使用方式
1、使用傳統的手動開始,手動提交事務即:beginTransaction()、commit()、rollback()等事務管理相關的方法,這就是編程式事務管理。
2、使用Transaction註解的聲明式事務,將事務的開啟和提交交給Spring容器完成,這個也是本次我使用的方式,簡單,但是使用時需要註意很多細節。
3、基於Spring AOP的切面的事務配置(本人很少使用這個,所以本文不重點刨析該知識點,想瞭解的可以到其他博客進行查看)
三、使用中遇到的問題
1、使用Transaction註解時拋出異常但是事務不起作用,異常時事務沒有進行回滾?
答:經過排查,查詢在開啟事務的方法中最外層使用瞭try…catch進行瞭異常的捕獲,因此拋出的異常本捕獲瞭,切面無法捕獲到異常,所以不會進行回滾。
解決:
(1) 手動指定切面捕獲的異常類型(因為默認情況下隻會在RuntimeExceptionimeException情況下才會進行事務的回滾),方式:@Transaction(rollbcackFor=Exception.class)
(2) 在catch中手動拋出一個運行時異常即:throw new RuntimeException();
(3) 如果需要在事務回滾時,給調用當前方法的調用者返回錯誤信息的話,用第二種方案就是不行的,因為拋出異常後的語句時不會執行的,包括return後面的語句,所以,此時可以手動進行事務回滾的語句調用即:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
2、剛插入的數據,無法馬上查詢到?
答: 這個問題是個大坑,整整苦惱瞭我兩天(可能是之前使用事務相關的知識比較少,所以遇到瞭根本就不知道是什麼原因),因為項目中使用的是MybatisPlus框架,一開始便懷疑是框架的緩存問題,因為剛插入馬上查詢時,查詢的SQL語句並沒有執行,即根本沒到數據庫去查,但是,手動關閉瞭緩存之後並沒起效果,最後大佬看瞭代碼後,一眼就指出問題所在(現在不得不感慨,經驗時多麼重要)。
要解決這個問題,首先要知道使用Transaction是怎麼進行事務增強的,說白瞭,是通過生成代理對象進行切面註入的,當前對象並沒有增強的作用,剛開始我插入和查詢的方法都是寫在一個service中,然後使用this調用這些方法,而this表示的是當前的service對象,所以這些方法根本就不在當前的事務中,因為剛插入的數據無法馬上查詢到0….0(我踩的大坑希望大傢不要再踩瞭,太難受瞭..)
解決方法:說瞭這麼多廢話,現在知道問題產生的原因,所以就好解決瞭:
(1) 將所有的數據庫操作方法抽取到另外一個Service對象中,然後通過@Autowire註入調用即可。
(2) 自己註入自己的對象即當前Service為A,可以直接使用:@Autowire private A a; 然後通過a調用相關數據庫操作的方法(註意不要使用this,使用this的話無效),@Autowire private A a這句話實際上返回的是當前Service的代理對象,但特別需要註意的是:所有操作數據庫相關的方法,訪問權限都需改成public,不然會出現mapper和service註入為null—這個是個大坑,具體原因還不知道(這個方式推薦使用)
(3) 使用:((A) AopContext.currentProxy()).方法名()進行調用(聽說這個方式在打包發佈的時候會出現問題,本次沒有試過這個方式,所以不推薦)
總結:
經驗就是一個積累的過程,沒有誰能夠一步登天,所以腳踏實地才是成功的秘訣。本文隻是本人在使用事務知識是遇到的問題的總結,希望能給大傢一個參考,也希望大傢多多支持WalkonNet!
推薦閱讀:
- SpringBoot對不同Bean註解的區別和使用場景說明
- SpringBoot中創建的AOP不生效的原因及解決
- SpringMVC中事務是否可以加在Controller層的問題
- 基於SpringBoot開機啟動與@Order註解
- Spring boot Jpa添加對象字段使用數據庫默認值操作