SpringBoot中@Transiactional注解沒有效果的解決
SpringBoot @Transiactional注解沒有效果
背景
數(shù)據(jù)庫為mysql
問題
使用SpringBoot操作數(shù)據(jù)庫插入兩條數(shù)據(jù),service層的方法出現(xiàn)了異常,按理說兩條數(shù)據(jù)都該插不進(jìn)去的,可以數(shù)據(jù)庫中卻還是有一條數(shù)據(jù)。
數(shù)據(jù)庫表格式:
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"); // 長度和數(shù)據(jù)庫的長度不符,會(huì)出異常 girlRepository.save(g2); } }
啟動(dòng)SpringBoot后,訪問對(duì)應(yīng)的方法,控制臺(tái)也報(bào)錯(cuò),但是表中是有一條數(shù)據(jù)的(原本是空表)。
查了查資料說的是在設(shè)計(jì)表的時(shí)候要選取的InnoDB引擎。
回頭看我的表引擎:
還真的是。。。。。。
解決
將數(shù)據(jù)表的引擎設(shè)置為InnoDB引擎。 然后再次執(zhí)行,@Transitional注解才起了作用,數(shù)據(jù)表中沒有了數(shù)據(jù)。
SpringBoot 使用Transaction注解遇到的坑
一、場景
開發(fā)一個(gè)多批次入庫的功能,功能中涉及到多個(gè)表間的操作,對(duì)數(shù)據(jù)庫表的操作要么同時(shí)成功,要么同時(shí)失敗,不然就會(huì)存在臟數(shù)據(jù),所以使用到了事務(wù)這個(gè)知識(shí)點(diǎn)()。
劃重點(diǎn):重要的都使用紅色標(biāo)出來了,大家如果不想看我廢話,直接跳到紅色字體即可0...0
二、Spring中使用的使用方式
1、使用傳統(tǒng)的手動(dòng)開始,手動(dòng)提交事務(wù)即:beginTransaction()、commit()、rollback()等事務(wù)管理相關(guān)的方法,這就是編程式事務(wù)管理。
2、使用Transaction注解的聲明式事務(wù),將事務(wù)的開啟和提交交給Spring容器完成,這個(gè)也是本次我使用的方式,簡單,但是使用時(shí)需要注意很多細(xì)節(jié)。
3、基于Spring AOP的切面的事務(wù)配置(本人很少使用這個(gè),所以本文不重點(diǎn)刨析該知識(shí)點(diǎn),想了解的可以到其他博客進(jìn)行查看)
三、使用中遇到的問題
1、使用Transaction注解時(shí)拋出異常但是事務(wù)不起作用,異常時(shí)事務(wù)沒有進(jìn)行回滾?
答:經(jīng)過排查,查詢?cè)陂_啟事務(wù)的方法中最外層使用了try...catch進(jìn)行了異常的捕獲,因此拋出的異常本捕獲了,切面無法捕獲到異常,所以不會(huì)進(jìn)行回滾。
解決:
(1) 手動(dòng)指定切面捕獲的異常類型(因?yàn)槟J(rèn)情況下只會(huì)在RuntimeExceptionimeException情況下才會(huì)進(jìn)行事務(wù)的回滾),方式:@Transaction(rollbcackFor=Exception.class)
(2) 在catch中手動(dòng)拋出一個(gè)運(yùn)行時(shí)異常即:throw new RuntimeException();
(3) 如果需要在事務(wù)回滾時(shí),給調(diào)用當(dāng)前方法的調(diào)用者返回錯(cuò)誤信息的話,用第二種方案就是不行的,因?yàn)閽伋霎惓:蟮恼Z句時(shí)不會(huì)執(zhí)行的,包括return后面的語句,所以,此時(shí)可以手動(dòng)進(jìn)行事務(wù)回滾的語句調(diào)用即:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
2、剛插入的數(shù)據(jù),無法馬上查詢到?
答: 這個(gè)問題是個(gè)大坑,整整苦惱了我兩天(可能是之前使用事務(wù)相關(guān)的知識(shí)比較少,所以遇到了根本就不知道是什么原因),因?yàn)轫?xiàng)目中使用的是MybatisPlus框架,一開始便懷疑是框架的緩存問題,因?yàn)閯偛迦腭R上查詢時(shí),查詢的SQL語句并沒有執(zhí)行,即根本沒到數(shù)據(jù)庫去查,但是,手動(dòng)關(guān)閉了緩存之后并沒起效果,最后大佬看了代碼后,一眼就指出問題所在(現(xiàn)在不得不感慨,經(jīng)驗(yàn)時(shí)多么重要)。
要解決這個(gè)問題,首先要知道使用Transaction是怎么進(jìn)行事務(wù)增強(qiáng)的,說白了,是通過生成代理對(duì)象進(jìn)行切面注入的,當(dāng)前對(duì)象并沒有增強(qiáng)的作用,剛開始我插入和查詢的方法都是寫在一個(gè)service中,然后使用this調(diào)用這些方法,而this表示的是當(dāng)前的service對(duì)象,所以這些方法根本就不在當(dāng)前的事務(wù)中,因?yàn)閯偛迦氲臄?shù)據(jù)無法馬上查詢到0....0(我踩的大坑希望大家不要再踩了,太難受了..)
解決方法:說了這么多廢話,現(xiàn)在知道問題產(chǎn)生的原因,所以就好解決了:
(1) 將所有的數(shù)據(jù)庫操作方法抽取到另外一個(gè)Service對(duì)象中,然后通過@Autowire注入調(diào)用即可。
(2) 自己注入自己的對(duì)象即當(dāng)前Service為A,可以直接使用:@Autowire private A a; 然后通過a調(diào)用相關(guān)數(shù)據(jù)庫操作的方法(注意不要使用this,使用this的話無效),@Autowire private A a這句話實(shí)際上返回的是當(dāng)前Service的代理對(duì)象,但特別需要注意的是:所有操作數(shù)據(jù)庫相關(guān)的方法,訪問權(quán)限都需改成public,不然會(huì)出現(xiàn)mapper和service注入為null---這個(gè)是個(gè)大坑,具體原因還不知道(這個(gè)方式推薦使用)
(3) 使用:((A) AopContext.currentProxy()).方法名()進(jìn)行調(diào)用(聽說這個(gè)方式在打包發(fā)布的時(shí)候會(huì)出現(xiàn)問題,本次沒有試過這個(gè)方式,所以不推薦)
總結(jié):
經(jīng)驗(yàn)就是一個(gè)積累的過程,沒有誰能夠一步登天,所以腳踏實(shí)地才是成功的秘訣。本文只是本人在使用事務(wù)知識(shí)是遇到的問題的總結(jié),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家!
相關(guān)文章
Java中使用websocket實(shí)現(xiàn)在線聊天功能
這篇文章主要介紹了Java中使用websocket實(shí)現(xiàn)在線聊天功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02JAVA中的函數(shù)式接口Function和BiFunction詳解
這篇文章主要介紹了JAVA中的函數(shù)式接口Function和BiFunction詳解,JDK的函數(shù)式接口都加上了@FunctionalInterface注解進(jìn)行標(biāo)識(shí),但是無論是否加上該注解只要接口中只有一個(gè)抽象方法,都是函數(shù)式接口,需要的朋友可以參考下2024-01-01Java線程中synchronized和volatile關(guān)鍵字的區(qū)別詳解
這篇文章主要介紹了Java線程中synchronized和volatile關(guān)鍵字的區(qū)別詳解,synchronzied既能夠保障可見性,又能保證原子性,而volatile只能保證可見性,無法保證原子性,volatile不需要加鎖,比synchronized更輕量級(jí),不會(huì)阻塞線程,需要的朋友可以參考下2024-01-01spring boot實(shí)現(xiàn)軟刪除的示例代碼
這篇文章主要介紹了spring boot實(shí)現(xiàn)軟刪除的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07Java實(shí)現(xiàn)直接插入排序與折半插入排序的示例詳解
這篇文章主要為大家詳細(xì)介紹了插入排序中兩個(gè)常見的排序:直接插入排序與折半插入排序。本文用Java語言實(shí)現(xiàn)了這兩個(gè)排序算法,感興趣的可以學(xué)習(xí)一下2022-06-06Java經(jīng)典算法匯總之選擇排序(SelectionSort)
選擇排序也是比較簡單的一種排序方法,原理也比較容易理解,選擇排序在每次遍歷過程中只記錄下來最小的一個(gè)元素的下標(biāo),待全部比較結(jié)束之后,將最小的元素與未排序的那部分序列的最前面一個(gè)元素交換,這樣就降低了交換的次數(shù),提高了排序效率。2016-04-04