@Transactional事务不起作用的解决

本文探讨了Spring中使用@Transactional注解配置事务管理时遇到的问题,并详细分析了配置文件及代码示例。文章指出,若数据库使用的是MyISAM存储引擎,则事务功能将无法正常工作,建议使用支持事务的InnoDB引擎。

问题

        使用spring的配置事物注解@Transactional,在测试的时候发现不起作用。

环境

       

         配置文件

[html]  view plain  copy
  1. <bean id="studentMGDataSource" class="org.apache.commons.dbcp.BasicDataSource"  
  2.     destroy-method="close">  
  3.     <property name="driverClassName" value="${student_MG_jdbc.driver}" />  
  4.     <property name="url" value="${student_MG_jdbc.url}" />  
  5.     <property name="username" value="${student_MG_jdbc.username}" />  
  6.     <property name="password" value="${student_MG_jdbc.password}" />  
  7.     <property name="initialSize" value="${student_MG_jdbc.initialSize}" />  
  8.     <property name="maxActive" value="${student_MG_jdbc.maxActive}" />  
  9.     <property name="maxIdle" value="${student_MG_jdbc.maxIdle}" />  
  10.     <property name="maxWait" value="${student_MG_jdbc.maxWait}" />  
  11.     <property name="defaultAutoCommit" value="${student_MG_jdbc.defaultAutoCommit}" />  
  12. </bean>  
  13.   
  14. <bean id="studentMGSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
  15.     <property name="configLocation" value="classpath:mybatis/mybatis-studentMG-config.xml" />  
  16.     <property name="dataSource" ref="studentMGDataSource" />  
  17. </bean>  
  18.   
  19. <bean id="studentMGSqlSession" class="org.mybatis.spring.SqlSessionTemplate">  
  20.     <constructor-arg index="0" ref="studentMGSqlSessionFactory" />  
  21. </bean>  
  22.   
  23. <bean id="studentMGTxManager"  
  24.     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
  25.     <property name="dataSource" ref="studentMGDataSource" />  
  26. </bean>  
  27.   
  28. <tx:annotation-driven proxy-target-class="true" transaction-manager="studentMGTxManager" />  

        Java代码

[java]  view plain  copy
  1. @Transactional(value="studentMGTxManager",rollbackFor=java.lang.Exception.class)  
  2. public void saveStudentDto(List<StudentDto> dtoList, String classId) {  
  3.       
  4. }  

原因

        数据库使用的存储引擎是MyISam,MyISam不支持事物,应该用InnoDB引擎

TIPS

        @Transactional注解事务不起作用的解决
         可能的原因:
        1.数据库引擎要支持事务
        如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的

        2.是否开启了对注解的解析
        配置文件必须加<tx:annotation-driven />,否则不解析@Transactional


<think>好的,用户问的是Spring Boot中方法自调用导致@Transactional事务失效的问题,需要解决方案。我之前整理过相关的引用资料,现在需要结合这些资料来思考如何回答。 首先,用户提供的引用里提到,Spring事务管理是基于AOP的动态代理机制。当自调用发生时,比如一个类中的方法A调用了方法B,而方法B有@Transactional注解,这时候事务会失效。因为自调用没有经过代理对象,而是直接调用了目标方法,绕过了Spring的AOP处理,导致事务注解没被拦截。 根据引用3中的例子,用户可能是在类内部通过this调用另一个事务方法,导致失效。解决方案需要确保调用的是代理对象的方法,而不是this的直接方法。比如引用2中的示例,通过自注入代理对象,然后在内部调用时使用这个代理对象来触发事务方法,这样就能让事务生效。 接下来,我需要总结几种常见的解决方案。首先想到的是自注入代理对象,也就是在类中注入自己的代理实例,然后通过这个代理来调用方法。这样调用会经过Spring的代理,触发事务管理。另外,使用AopContext.currentProxy()方法获取当前代理对象也是一个办法,不过需要开启AspectJ的暴露代理功能。还有,可以将事务方法拆分到另一个Service类中,通过外部调用避免自调用问题。此外,配置文件中启用暴露代理也是一个需要注意的点。 需要检查用户的问题是否还有其他可能的解决方案,比如引用1中提到的PROPAGATION_REQUIRED传播机制,但自调用情况下传播机制可能无法生效,因为事务的上下文没有被正确传递。所以重点还是确保调用的是代理对象。 另外,用户可能需要具体的代码示例,比如如何自注入代理对象,或者如何配置AopContext。需要详细说明每个步骤,确保用户能够理解和实施。 还要注意,使用@Async和@Transactional一起使用时,同样的问题会出现,所以引用2中的解决方法可能也适用,即通过代理对象调用事务方法。同时,用户可能对为什么自调用会失效有疑问,所以需要解释清楚Spring的AOP机制和动态代理的原理。 最后,要确保回答结构清晰,分点列出解决方案,每个方案都有具体步骤和示例代码,方便用户参考。可能还需要提醒用户在使用自注入时注意循环依赖的问题,或者使用AopContext时的配置要求。</think>在Spring Boot中解决自调用导致@Transactional事务失效的问题,需理解其根本原因和对应策略。以下是具体解决方案及实现步骤: --- ### 一、问题原因分析 Spring事务基于动态代理实现,自调用(类内部方法相互调用)会绕过代理对象,导致事务注解失效。例如: ```java public void methodA() { this.methodB(); // 直接调用本类方法,事务失效 } @Transactional public void methodB() { // 事务操作... } ``` --- ### 二、解决方案汇总 #### 1. 自注入代理对象(推荐) 通过注入本类的代理对象调用事务方法: ```java @Service public class MyService { // 注入自身代理对象 private MyService proxySelf; @PostConstruct public void initProxy() { proxySelf = SpringContextHolder.getBean(MyService.class); } public void methodA() { proxySelf.methodB(); // 通过代理对象调用事务方法 ✅ } @Transactional public void methodB() { // 事务操作... } } ``` #### 2. 使用AopContext获取当前代理 通过AopContext暴露代理对象调用方法: ```java // 第一步:配置类开启暴露代理 @EnableAspectJAutoProxy(exposeProxy = true) public class AppConfig {} // 第二步:调用时获取代理对象 public void methodA() { ((MyService) AopContext.currentProxy()).methodB(); // 通过代理调用 ✅ } ``` #### 3. 事务方法拆分到其他Service 将事务方法独立到另一个Service类中,通过外部调用避免自调用: ```java @Service public class ServiceA { @Autowired private ServiceB serviceB; public void methodA() { serviceB.methodB(); // 跨类调用事务方法 ✅ } } @Service public class ServiceB { @Transactional public void methodB() { // 事务操作... } } ``` #### 4. 强制使用CGLIB代理(兼容性增强) 在配置文件中明确指定代理方式: ```properties # application.properties spring.aop.proxy-target-class=true ``` --- ### 三、关键原理说明 1. **动态代理机制** Spring通过JDK动态代理或CGLIB生成代理对象,只有通过代理对象调用方法时,事务拦截器才会生效[^3]。 2. **自调用问题本质** 自调用时使用`this.method()`会直接调用原始对象的方法,而非代理对象,导致事务拦截器未被触发[^3]。 3. **代理对象注入必要性** 通过注入自身代理对象或使用`AopContext`,可确保调用链经过代理对象,从而激活事务管理[^2]。 --- ### 四、选择建议 1. **小型项目**:推荐自注入代理对象(方案1),实现简单且代码直观。 2. **复杂调用链**:使用AopContext(方案2)或拆分Service(方案3),增强可维护性。 3. **遗留代码改造**:优先采用CGLIB代理(方案4),减少代码侵入性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值