@Transactional 常用属性和失效的几种情况
常用属性
propagation:事务传播行为
举个例子:我们在 A 类的aMethod()方法中调用了 B 类的 bMethod() 方法。这个时候就涉及到业务层方法之间互相调用的事务问题。如果我们的 bMethod()如果发生异常需要回滚,如何配置事务传播行为才能让 aMethod()也跟着回滚呢?这个时候就需要事务传播行为的知识了
参考链接:https://blog.csdn.net/hhb442/article/details/134980521
@Service public class TopService { @Autowired private StudentService studentService; //测试 事务的传播行为 @Transactional public void topService(){ studentService.changeAge(); studentService.changeName(); } } @Service public class StudentService { @Autowired private StudentDao studentDao; //事务的传播行为 @Transactional public void changeAge(){ studentDao.updateAgeById(998, 1); } //事务的传播行为, @Transactional public void changeName(){ studentDao.updateNameById("dasdas", 1); int i = 1/0; } }
默认Propagation.REQUIRED(如果父方法有事务,就加入父方法事务,如果没有就新建自己独立的事务)
下面代码中是父方法有事务的情况,propagation 设置为Propagation.REQUIRED,在topService()中调用了studentService.changeAge()和studentService.changeName(),因为事务传播行为为REQUIRED,所以changeAge()和changeName()方法在同一个事务中。
此时changeName()发生运行时异常,两个方法同时回滚, 年龄和名字均不会被修改。
@Service public class TopService { @Autowired private StudentService studentService; //测试 事务的传播行为 @Transactional public void topService(){ studentService.changeAge(); studentService.changeName(); } } @Service public class StudentService { @Autowired private StudentDao studentDao; //事务的传播行为 @Transactional(propagation = Propagation.REQUIRED) public void changeAge(){ studentDao.updateAgeById(998, 1); } //事务的传播行为, @Transactional(propagation = Propagation.REQUIRED) public void changeName(){ studentDao.updateNameById("dasdas", 1); int i = 1/0; } }
Propagation.REQUIRES_NEW(不管父方法是否有事务,我都新建事务,都是独立的,子方法都是独立的事务)
不管父方法是否有事务,我都新建事务,都是独立的,子方法都是独立的事务
下面代码中,propagation 设置为Propagation.REQUIRES_NEW,在topService()中调用了studentService.changeAge()和studentService.changeName(),因为事务传播行为为REQUIRES_NEW,所以changeAge()和changeName() 子方法是两个独立的事务
此时changeName()发生运行时异常,changeName()发生回滚,不会影响changeAge()方法,年龄将被修改,名字不会修改。
@Service public class TopService { @Autowired private StudentService studentService; //测试 事务的传播行为 @Transactional public void topService(){ studentService.changeAge(); studentService.changeName(); } } @Service public class StudentService { @Autowired private StudentDao studentDao; //事务的传播行为 @Transactional(propagation = Propagation.REQUIRES_NEW) public void changeAge(){ studentDao.updateAgeById(998, 1); } //事务的传播行为, @Transactional(propagation = Propagation.REQUIRES_NEW) public void changeName(){ studentDao.updateNameById("dasdas", 1); int i = 1/0; } }
失效情况
第一种 Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用.
原因:@Transactional是基于动态代理实现的,不是public的方法不会创建代理对象
第二种 在类内部调用调用类内部@Transactional标注的方法。这种情况下也会导致事务不开启
@Component public class TestServiceImpl implements TestService { @Resource TestMapper testMapper; @Transactional public void fun2() { }
@Transactional
public void fun1(){ //类内部调用@Transactional标注的方法。
fun2();
}
}
原因:在类的内部调用内部方法是通过this对象调的,相当于this.fun2(),没有走动态代理,
解决办法:1 获取当前类的代理对象: ITestService proxy=(ITestService) AopContext.currentProxy();2 通过代理对像调@transactional方法 : proxy.fun2()
第三种 事务方法内部捕捉了异常,没有抛出新的异常,导致事务操作不会进行回滚
@Component public class TestServiceImpl implements TestService { @Resource TestMapper testMapper; @Transactional public void insertTestCatchException() { try { xxxx
//运行期间抛异常
throw new NeedToInterceptException("");
}catch (Exception e){ System.out.println(""); //catch捕获了Exception 异常,但没抛出异常
} } }
第四中 多线程/异步场景
@Transactional public void doSomething() { new Thread(() -> { // 这个事务不起作用 updateData(); }).start(); }
浙公网安备 33010602011771号