Springboot中嵌套事务失效原因分析 冷不防 2021-12-21 11:49 251阅读 0赞 # Springboot中嵌套事务失效原因分析 # 首先两个事务方法,其中一个调用另一个。 @Transactional(rollbackFor = Exception.class) public void trance() { try { trance1();//调用下一个事务方法。 } catch (Exception e) { e.printStackTrace(); } User user = new User(); ShardingIDConfig shardingIDConfig = new ShardingIDConfig(); user.setId(shardingIDConfig.generateKey().longValue()); user.setName("trance"); user.setSex(0); userMapper.create(user); } @Transactional(propagation = Propagation.REQUIRED) public void trance1() throws Exception{ User user = new User(); ShardingIDConfig shardingIDConfig = new ShardingIDConfig(); user.setId(shardingIDConfig.generateKey().longValue()); user.setName("trance1"); user.setSex(1); userMapper.create(user); System.out.println(user.getId()); throw new RuntimeException(); } 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> 然后写个测试类,我也是第一次用这个测试 import com.lijia.App; import com.lijia.service.UserService; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest(classes = App.class) public class Test { @Autowired private UserService userService; @org.junit.Test public void trance(){ userService.trance(); } } 执行会发现报了RuntimeException,但是数据库里面有两条数据,说明事务失效了 ![webp][] runtimeException ![webp 1][] 数据库两条数据都上传了,说明事务失效 **为什么会出现这种情况呢** spring事务使用了动态代理。还是从动态代理去看。 给出一段代码 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface IHello { public void test(); public void test1(); } class Hello implements IHello{ @Override public void test() { System.out.println("test"); } @Override public void test1() { System.out.println("test1"); } } public class MyInvoke implements InvocationHandler{ public Object target; public MyInvoke(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().contains("test")){ System.out.println("========代理了======="); } return method.invoke(target,args); } public static void main(String[] args) { MyInvoke myInvoke = new MyInvoke(new Hello()); IHello iHello = (IHello) Proxy.newProxyInstance(MyInvoke.class.getClassLoader(),new Class[]{IHello.class},myInvoke); iHello.test(); iHello.test1(); } } 运行结果是 ![webp 2][] 将上面的`Hello类`中的`test1方法`放入`test方法`中 public void test() { test1(); System.out.println("test"); } ![webp 3][] 回到上面的问题,会发现`trance1()`没有走代理,所以会出现两个都插入数据库的操作。 那么需要得到当前的代理对象,然后调用`trance1()` 通过`AopContext.currentProxy()`获得当前代理 ((UserService)AopContext.currentProxy()).trance1(); 改成这样调用`trance1()` 运行Test,然后数据库就剩一条数据了,说明`trance1()`方法回滚了。 [webp]: /images/20211220/88c8034f5b8248baaef80a95b30d22b5.png [webp 1]: /images/20211220/ed4cf8d5978249d28c334454c35cc5d9.png [webp 2]: /images/20211220/f07d6ce712364cf4bdef34145b13c049.png [webp 3]: /images/20211220/365671bfa9294a7c9c06084df2bcfa1f.png
还没有评论,来说两句吧...