聊聊spring|聊聊spring @Transactional 事务无法使用的可能原因
spring transaction
建议
Spring
团队的建议是你在具体的类(或类的方法)上使用 @Transactional
注解,
而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional
注解,
但是这将只能当你设置了基于接口的代理时它才生效。
因为注解是不能继承的,
这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,
而且对象也将不会被事务代理所包装(将被确认为严重的)。
因此请接受Spring
团队的建议并且在具体的类上使用 @Transactional
注解。
事务无法使用的可能原因
导入spring的事务注解
应该是
org.springframework.transaction.annotation.Transactional
而不是
javax.transaction.Transactional
是否开启了对注解的解析:
xml
文件配置springboot
注解开启自动扫描
@EnableTransactionManagement
spring
是否扫描到你使用注解事务的这个类所在的包配置
xml
springboot
开启事务@EnableTransactionManagement
数据库引擎要支持事务
如果是
mysql
,注意表要使用支持事务的引擎,比如InnoDB
,如果是myisam
,事务是不起作用的springboot
的配置spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
检查方法是不是public的
@Transactional
仅仅在 public
方法,才能进行事务管理。文章图片
这是因为在使用
Spring AOP
代理时,Spring
在调用在图中的 TransactionInterceptor
在目标方法执行前后进行拦截之前(图中是cglib
代理)DynamicAdvisedInterceptor(CglibAopProxy 的内部类)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法会间接调用 AbstractFallbackTransactionAttributeSource ,而会去调用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
层捕捉异常后,发现事务不生效。在
Service
层手工捕捉并处理了异常(try…catch
)等于把异常吃掉了,Spring
自然不知道这里有错,更不会主动去回滚数据。推荐做法是在Service
层统一抛出异常,然后在
Controll
层统一处理。下面代码事务是无法生效的
//在类上@Transactional 说明,所以public都是有事务的@Service@Transactionalpublic 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 的自调用问题
检查是不是同一个类中的方法调用(如a方法调用同一个类中的b方法),从而避免
Spring
的 AOP
的自调用问题这是因为在
Spring
的 AOP
代理下,只有目标方法由外部调用,目标方法才由
Spring
生成的代理对象来管理,这会造成自调用问题。若同一类中的其他没有
@Transactional
注解的方法内部调用有@Transactional
注解的方法,有
@Transactional
注解的方法的事务被忽略,不会发生回滚。@Servicepublic 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
代理【聊聊spring|聊聊spring @Transactional 事务无法使用的可能原因】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 2018-07-09|2018-07-09 Spring 的DBCP,c3p0
- 想聊聊SA,聊聊手帐,也想和你们分享自己
- spring|spring boot项目启动websocket
- Spring|Spring Boot 整合 Activiti6.0.0
- Spring集成|Spring集成 Mina
- springboot使用redis缓存
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了