Springboot中嵌套事务失效分析 分析Springboot中嵌套事务失效原因详解
秋天的春 人气:0想了解分析Springboot中嵌套事务失效原因详解的相关内容吗,秋天的春在本文为您仔细讲解Springboot中嵌套事务失效分析的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Springboot中嵌套事务失效分析,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,但是数据库里面有两条数据,说明事务失效了
runtimeException
数据库两条数据都上传了,说明事务失效
为什么会出现这种情况呢
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(); } }
将上面的Hello类
中的test1方法
放入test方法
中
public void test() { test1(); System.out.println("test"); }
回到上面的问题,会发现trance1()
没有走代理,所以会出现两个都插入数据库的操作。
那么需要得到当前的代理对象,然后调用trance1()
通过AopContext.currentProxy()
获得当前代理
((UserService)AopContext.currentProxy()).trance1();
改成这样调用trance1()
运行Test,然后数据库就剩一条数据了,说明trance1()
方法回滚了。
加载全部内容