聊聊spring @Transactional 事務(wù)無(wú)法使用的可能原因
spring transaction
建議
Spring團(tuán)隊(duì)的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,
而不要使用在類所要實(shí)現(xiàn)的任何接口上。你當(dāng)然可以在接口上使用 @Transactional 注解,
但是這將只能當(dāng)你設(shè)置了基于接口的代理時(shí)它才生效。
因?yàn)樽⒔馐遣荒芾^承的,
這就意味著如果你正在使用基于類的代理時(shí),那么事務(wù)的設(shè)置將不能被基于類的代理所識(shí)別,
而且對(duì)象也將不會(huì)被事務(wù)代理所包裝(將被確認(rèn)為嚴(yán)重的)。
因此請(qǐng)接受Spring團(tuán)隊(duì)的建議并且在具體的類上使用 @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è)類所在的包
配置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)部類)的的 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
異常類型是不是unchecked異常
默認(rèn),只有unchecked異常時(shí)才回滾該事務(wù)
spring只有在拋出的異常為運(yùn)行時(shí)unchecked異常時(shí)才回滾該事務(wù),
也就是拋出的異常為RuntimeException的子類(Errors也會(huì)導(dǎo)致事務(wù)回滾).
而拋出checked異常則不會(huì)導(dǎo)致事務(wù)回滾。可以明確的配置在拋出那些異常時(shí)回滾事務(wù),
包括checked異常。也可以明確定義那些異常拋出時(shí)不回滾事務(wù)。
如果想讓checked異常也回滾,在注解上面寫(xiě)明異常類型即可:
@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ú)法生效的
//在類上@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è)類中的方法調(diào)用(如a方法調(diào)用同一個(gè)類中的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)題。
若同一類中的其他沒(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)文章
SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))
這篇文章主要介紹了SpringBoot之使用Redis實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
SpringMVC通過(guò)注解獲得參數(shù)的實(shí)例
下面小編就為大家?guī)?lái)一篇SpringMVC通過(guò)注解獲得參數(shù)的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
SpringBoot實(shí)現(xiàn)國(guó)際化的教程
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)國(guó)際化的教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
SpringBoot整合Shiro實(shí)現(xiàn)權(quán)限控制的代碼實(shí)現(xiàn)
Apache Shiro是一個(gè)強(qiáng)大且易用的Java安全框架,執(zhí)行身份驗(yàn)證、授權(quán)、密碼和會(huì)話管理,今天通過(guò)本文給大家介紹SpringBoot整合Shiro實(shí)現(xiàn)權(quán)限控制的方法,感興趣的朋友一起看看吧2021-07-07

