聊聊spring @Transactional 事務(wù)無(wú)法使用的可能原因
spring transaction
建議
Spring
團(tuán)隊(duì)的建議是你在具體的類(lèi)(或類(lèi)的方法)上使用 @Transactional
注解,
而不要使用在類(lèi)所要實(shí)現(xiàn)的任何接口上。你當(dāng)然可以在接口上使用 @Transactional
注解,
但是這將只能當(dāng)你設(shè)置了基于接口的代理時(shí)它才生效。
因?yàn)樽⒔馐遣荒芾^承的,
這就意味著如果你正在使用基于類(lèi)的代理時(shí),那么事務(wù)的設(shè)置將不能被基于類(lèi)的代理所識(shí)別,
而且對(duì)象也將不會(huì)被事務(wù)代理所包裝(將被確認(rèn)為嚴(yán)重的)。
因此請(qǐng)接受Spring
團(tuán)隊(duì)的建議并且在具體的類(lèi)上使用 @Transactional
注解。
事務(wù)無(wú)法使用的可能原因
導(dǎo)入spring的事務(wù)注解
應(yīng)該是
org.springframework.transaction.annotation.Transactional
而不是
javax.transaction.Transactional
是否開(kāi)啟了對(duì)注解的解析:
xml
文件配置
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
springboot
注解開(kāi)啟自動(dòng)掃描
@EnableTransactionManagement
spring
是否掃描到你使用注解事務(wù)的這個(gè)類(lèi)所在的包
配置xml
<context:component-scan base-package="com.xxx.xxx" ></context:component-scan>
springboot
開(kāi)啟事務(wù)
@EnableTransactionManagement
數(shù)據(jù)庫(kù)引擎要支持事務(wù)
如果是mysql
,注意表要使用支持事務(wù)的引擎,比如InnoDB
,如果是myisam
,事務(wù)是不起作用的
springboot
的配置
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
檢查方法是不是public的
@Transactional
僅僅在 public
方法,才能進(jìn)行事務(wù)管理。
這是因?yàn)樵谑褂?Spring AOP
代理時(shí),
Spring
在調(diào)用在圖中的 TransactionInterceptor
在目標(biāo)方法執(zhí)行前后進(jìn)行攔截之前(圖中是cglib
代理)
DynamicAdvisedInterceptor(CglibAopProxy 的內(nèi)部類(lèi))的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法會(huì)間接調(diào)用 AbstractFallbackTransactionAttributeSource ,而會(huì)去調(diào)用computeTransactionAttribute 方法。
protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } }
這個(gè)方法會(huì)判斷如果不是 public
則會(huì)返回 null
異常類(lèi)型是不是unchecked異常
默認(rèn),只有unchecked
異常時(shí)才回滾該事務(wù)
spring
只有在拋出的異常為運(yùn)行時(shí)unchecked
異常時(shí)才回滾該事務(wù),
也就是拋出的異常為RuntimeException
的子類(lèi)(Errors
也會(huì)導(dǎo)致事務(wù)回滾).
而拋出checked
異常則不會(huì)導(dǎo)致事務(wù)回滾??梢悦鞔_的配置在拋出那些異常時(shí)回滾事務(wù),
包括checked
異常。也可以明確定義那些異常拋出時(shí)不回滾事務(wù)。
如果想讓checked
異常也回滾,在注解上面寫(xiě)明異常類(lèi)型即可:
@Transactional (rollbackFor=Exception.class)
noRollbackFor
自定義不回滾的異常
異常是不是被catch住了
在Service
層捕捉異常后,發(fā)現(xiàn)事務(wù)不生效。
在Service
層手工捕捉并處理了異常(try…catch
)等于把異常吃掉了,
Spring
自然不知道這里有錯(cuò),更不會(huì)主動(dòng)去回滾數(shù)據(jù)。推薦做法是在Service
層統(tǒng)一拋出異常,
然后在Controll
層統(tǒng)一處理。
下面代碼事務(wù)是無(wú)法生效的
//在類(lèi)上@Transactional 說(shuō)明,所以public都是有事務(wù)的 @Service @Transactional public class StudentService { @Autowired private GroupRepository groupRepository; @Autowired private InstituteRepository instituteRepository; public void initStudent() { Institute institute = Institute.builder().build(); institute.setCode("TEST4"); instituteRepository.save(institute); // 這里自己處理異常,spring不會(huì)知道存在異常,無(wú)法進(jìn)行事務(wù)回滾 try { throw new RuntimeException("運(yùn)行時(shí)異常----------看事務(wù)是否起作用"); } catch (Exception e) { e.printStackTrace(); } } }
修改成如下代碼
public void initStudent() throws Exception{ Institute institute = Institute.builder().build(); institute.setCode("TEST4"); instituteRepository.save(institute); groupRepository.save(group); //不進(jìn)行異常處理,而是把異常拋出 throw new RuntimeException("運(yùn)行時(shí)異常----------看事務(wù)是否起作用"); }
避免 Spring 的 AOP 的自調(diào)用問(wèn)題
檢查是不是同一個(gè)類(lèi)中的方法調(diào)用(如a方法調(diào)用同一個(gè)類(lèi)中的b方法),從而避免 Spring
的 AOP
的自調(diào)用問(wèn)題
這是因?yàn)樵?Spring
的 AOP
代理下,只有目標(biāo)方法由外部調(diào)用,
目標(biāo)方法才由 Spring
生成的代理對(duì)象來(lái)管理,這會(huì)造成自調(diào)用問(wèn)題。
若同一類(lèi)中的其他沒(méi)有@Transactional
注解的方法內(nèi)部調(diào)用有@Transactional
注解的方法,
有@Transactional
注解的方法的事務(wù)被忽略,不會(huì)發(fā)生回滾。
@Service public class StudentService { @Autowired private GroupRepository groupRepository; @Autowired private InstituteRepository instituteRepository; //initStudent() 加上@Transactional(),則會(huì)回滾 public void initStudent() throws Exception{ Institute institute = Institute.builder().build(); institute.setCode("TEST4"); instituteRepository.save(institute); //雖然 initGroup() 有 @Transactional() 但是事務(wù)還是沒(méi)起作用 initGroup(); throw new RuntimeException("運(yùn)行時(shí)異常----------看事務(wù)是否起作用"); } @Transactional() public void initGroup() { Group group = Group.builder().academic_year(2015).build(); group.setCode("ELSE1"); groupRepository.save(group); } }
AspectJ
取代 Spring AOP
代理
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 一文搞懂spring boot本地事務(wù)@Transactional參數(shù)
- spring 中事務(wù)注解@Transactional與trycatch的使用
- Spring事務(wù)注解@Transactional失效的八種場(chǎng)景分析
- Spring聲明式事務(wù)@Transactional知識(shí)點(diǎn)分享
- springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場(chǎng)景
- 淺談Spring中@Transactional事務(wù)回滾及示例(附源碼)
- 解析spring事務(wù)管理@Transactional為什么要添加rollbackFor=Exception.class
相關(guān)文章
SpringCloud實(shí)現(xiàn)服務(wù)調(diào)用feign與熔斷hystrix和網(wǎng)關(guān)gateway詳細(xì)分析
這篇文章主要介紹了SpringCloud實(shí)現(xiàn)服務(wù)調(diào)用feign與熔斷hystrix和網(wǎng)關(guān)gateway,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-04-04AsyncConfigurerSupport自定義異步線(xiàn)程池處理異常
這篇文章主要為大家介紹了AsyncConfigurerSupport自定義異步線(xiàn)程池處理異常詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06深入解析Apache Kafka實(shí)時(shí)流處理平臺(tái)
這篇文章主要為大家介紹了Apache Kafka實(shí)時(shí)流處理平臺(tái)深入解析,從基本概念到實(shí)戰(zhàn)操作詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01Java 如何快速,優(yōu)雅的實(shí)現(xiàn)導(dǎo)出Excel
這篇文章主要介紹了Java 如何快速,優(yōu)雅的實(shí)現(xiàn)導(dǎo)出Excel,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下2021-03-03Java發(fā)送http請(qǐng)求的示例(get與post方法請(qǐng)求)
這篇文章主要介紹了Java發(fā)送http請(qǐng)求的示例(get與post方法請(qǐng)求),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01