聊聊spring @Transactional 事務無法使用的可能原因
spring transaction
建議
Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,
而不要使用在類所要實現(xiàn)的任何接口上。你當然可以在接口上使用 @Transactional 注解,
但是這將只能當你設置了基于接口的代理時它才生效。
因為注解是不能繼承的,
這就意味著如果你正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,
而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。
因此請接受Spring團隊的建議并且在具體的類上使用 @Transactional 注解。
事務無法使用的可能原因
導入spring的事務注解
應該是
org.springframework.transaction.annotation.Transactional
而不是
javax.transaction.Transactional
是否開啟了對注解的解析:
xml 文件配置
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
springboot
注解開啟自動掃描
@EnableTransactionManagement
spring是否掃描到你使用注解事務的這個類所在的包
配置xml
<context:component-scan base-package="com.xxx.xxx" ></context:component-scan>
springboot 開啟事務
@EnableTransactionManagement
數(shù)據(jù)庫引擎要支持事務
如果是mysql,注意表要使用支持事務的引擎,比如InnoDB,如果是myisam,事務是不起作用的
springboot的配置
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
檢查方法是不是public的
@Transactional 僅僅在 public 方法,才能進行事務管理。

這是因為在使用 Spring AOP 代理時,
Spring 在調(diào)用在圖中的 TransactionInterceptor 在目標方法執(zhí)行前后進行攔截之前(圖中是cglib代理)
DynamicAdvisedInterceptor(CglibAopProxy 的內(nèi)部類)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法會間接調(diào)用 AbstractFallbackTransactionAttributeSource ,而會去調(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;
}
}
這個方法會判斷如果不是 public 則會返回 null
異常類型是不是unchecked異常
默認,只有unchecked異常時才回滾該事務
spring只有在拋出的異常為運行時unchecked異常時才回滾該事務,
也就是拋出的異常為RuntimeException的子類(Errors也會導致事務回滾).
而拋出checked異常則不會導致事務回滾??梢悦鞔_的配置在拋出那些異常時回滾事務,
包括checked異常。也可以明確定義那些異常拋出時不回滾事務。
如果想讓checked異常也回滾,在注解上面寫明異常類型即可:
@Transactional (rollbackFor=Exception.class)
noRollbackFor 自定義不回滾的異常
異常是不是被catch住了
在Service層捕捉異常后,發(fā)現(xiàn)事務不生效。
在Service層手工捕捉并處理了異常(try…catch)等于把異常吃掉了,
Spring自然不知道這里有錯,更不會主動去回滾數(shù)據(jù)。推薦做法是在Service層統(tǒng)一拋出異常,
然后在Controll層統(tǒng)一處理。
下面代碼事務是無法生效的
//在類上@Transactional 說明,所以public都是有事務的
@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不會知道存在異常,無法進行事務回滾
try {
throw new RuntimeException("運行時異常----------看事務是否起作用");
} catch (Exception e) {
e.printStackTrace();
}
}
}
修改成如下代碼
public void initStudent() throws Exception{
Institute institute = Institute.builder().build();
institute.setCode("TEST4");
instituteRepository.save(institute);
groupRepository.save(group);
//不進行異常處理,而是把異常拋出
throw new RuntimeException("運行時異常----------看事務是否起作用");
}
避免 Spring 的 AOP 的自調(diào)用問題
檢查是不是同一個類中的方法調(diào)用(如a方法調(diào)用同一個類中的b方法),從而避免 Spring 的 AOP 的自調(diào)用問題
這是因為在 Spring 的 AOP 代理下,只有目標方法由外部調(diào)用,
目標方法才由 Spring 生成的代理對象來管理,這會造成自調(diào)用問題。
若同一類中的其他沒有@Transactional 注解的方法內(nèi)部調(diào)用有@Transactional 注解的方法,
有@Transactional 注解的方法的事務被忽略,不會發(fā)生回滾。
@Service
public class StudentService {
@Autowired
private GroupRepository groupRepository;
@Autowired
private InstituteRepository instituteRepository;
//initStudent() 加上@Transactional(),則會回滾
public void initStudent() throws Exception{
Institute institute = Institute.builder().build();
institute.setCode("TEST4");
instituteRepository.save(institute);
//雖然 initGroup() 有 @Transactional() 但是事務還是沒起作用
initGroup();
throw new RuntimeException("運行時異常----------看事務是否起作用");
}
@Transactional()
public void initGroup() {
Group group = Group.builder().academic_year(2015).build();
group.setCode("ELSE1");
groupRepository.save(group);
}
}
AspectJ 取代 Spring AOP 代理
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringCloud實現(xiàn)服務調(diào)用feign與熔斷hystrix和網(wǎng)關(guān)gateway詳細分析
這篇文章主要介紹了SpringCloud實現(xiàn)服務調(diào)用feign與熔斷hystrix和網(wǎng)關(guān)gateway,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2023-04-04
AsyncConfigurerSupport自定義異步線程池處理異常
這篇文章主要為大家介紹了AsyncConfigurerSupport自定義異步線程池處理異常詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
Java 如何快速,優(yōu)雅的實現(xiàn)導出Excel
這篇文章主要介紹了Java 如何快速,優(yōu)雅的實現(xiàn)導出Excel,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下2021-03-03
Java發(fā)送http請求的示例(get與post方法請求)
這篇文章主要介紹了Java發(fā)送http請求的示例(get與post方法請求),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01

