在之前解释Spring事物不生效时,列举了很多方面的原则,详细参考
Spring事物不生效的原因
http://www.javacui.com/framework/560.html
其中说到了一点:在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启。
假如有如下实例类:
@Service public class T1ServiceImpl extends ServiceImpl<T1EntityMapper, T1Entity> implements T1Service { @Autowired private T2Service t2Service; @Override public void insertT1() { doInsert(); } @Transactional(rollbackFor = Exception.class) public void doInsert(){ T1Entity t1Entity = new T1Entity(); t1Entity.setName("t1"); T2Entity t2Entity = new T2Entity(); t2Entity.setName("t2"); save(t1Entity); System.out.println(1/0); t2Service.save(t2Entity); } }
如上模拟了一个异常,因为是运行时异常,所以增加注解rollbackFor,原因不生效那篇里面也说过:
(6)注解为事务范围的方法中,事务的回滚仅仅对于unchecked的异常有效。对于checked异常无效。也就是说事务回滚仅仅发生在出现RuntimeException或Error的时候。如果希望一般的异常也能触发事务回滚,需要在注解了@Transactional的方法上,将@Transactional回滚参数设置。
那么调用insertT1()时,insertT1()调用doInsert(),虽然该方法标记了事物,但是实际上事物是不起作用的。
如果要解决这个问题,要么就是再写一个Service,要么就是写到一个方法里面,即一定要使用Spring代理来调用这个方法,否则Spring无法帮我们处理事物。
但是如果你一定要这样写,而且要在一个Service里面,那么可以通过如下方式解决:
首先拿到当前对象的代理对象,一般你在哪个ServiceImpl里面,就是哪个Service,然后通过代理对象进行调用,例如:
package com.example.springboot.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.springboot.entity.T1Entity; import com.example.springboot.entity.T2Entity; import com.example.springboot.mapper.T1EntityMapper; import com.example.springboot.service.T1Service; import com.example.springboot.service.T2Service; import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class T1ServiceImpl extends ServiceImpl<T1EntityMapper, T1Entity> implements T1Service { @Autowired private T2Service t2Service; @Override public void insertT1() { T1Service t1Service = (T1Service)AopContext.currentProxy(); t1Service.doInsert(); } @Transactional(rollbackFor = Exception.class) public void doInsert(){ T1Entity t1Entity = new T1Entity(); t1Entity.setName("t1"); T2Entity t2Entity = new T2Entity(); t2Entity.setName("t2"); save(t1Entity); System.out.println(1/0); t2Service.save(t2Entity); } }
POM引入
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
SpringBoot启动的话,要增加一个注解
@EnableAspectJAutoProxy(exposeProxy = true)
如下
package com.example.springboot; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableAspectJAutoProxy; @EnableAspectJAutoProxy(exposeProxy = true) @MapperScan("com.example.springboot.mapper") @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
这样就成了,这个方法也是通过代理进行调用的,事物才会正常生效。
END
Java小强
未曾清贫难成人,不经打击老天真。
自古英雄出炼狱,从来富贵入凡尘。
发表评论: