假设我有一个Service叫做A,另一个Service 叫做B。
(1) A中事务a1调用A中事务a2
(2) A中事务a1调用B中事务b1
- (1)(2)有区别吗?
- 几种事务传播机制的区别。
配置事务是只配置当前方法与调用它的方法之间的传播关系,而不是当前方法和它里面的方法之间的关系。即有甲乙丙三个方法。甲调用乙,乙再调用丙,在乙方法上面配置的事务传播,只是针对甲乙之间的传播关系,而不是乙丙之间的传播关系。乙丙之间的传播关系,应该在丙上面配置。
一、 (1)(2)有区别吗
有区别
。请看事务传播的requires_new。
二、事务的传播
Propagation.REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。这里传播方式很好理解。不过,我还是写个例子测试一波。
@Service
@Service
public class AImpl implements A {
@Autowired
private UserMapper userDao;
@Transactional
@Override
public void a1() {
userDao.insert(1,"user1");
a2();
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void a2() {
userDao.insert(2,"user2");
throw new RuntimeException("抛个可爱的异常!");
}
}
测试代码:
@SpringBootTest
@RunWith(SpringRunner.class)
public class Test {
@Autowired
private A a;
@Autowired
private B b;
@org.junit.Test
public void test(){
/*A中事务a1调用a2*/
a.a1();
}
}
我在a1中调用了a2,a1存在事务。而我定义a2的事务传播方式为Propagation.REQUIRED
,当a2发现当前存在事务时,不会在创建一个事务。所以,当a2中发生异常后,a1、a2都会回滚的。运行结果如图1所示
Propagation.REQUIRES_NEW
总是开启一个事务。父事务不会影响子事务,子事务会影响父事务(子事务通过抛出异常影响)。除非父事务捕获了自事务抛出的异常,否则父事务也会回滚。
@Service
public class AImpl implements A {
@Autowired
private UserMapper userMapper;
@Transactional
@Override
public void a1() {
userMapper.insert(1,"user1");
try {
a2();
}catch (Exception e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void a2() {
userMapper.insert(2,"user2");
throw new RuntimeException("抛个可爱的异常!");
}
}
运行结果如图2所示。
按道理只会插入user1,为什么插入了user2。难道在同一个service中使用requires_new方式,a1调用a2不行。于是我将a1调用a2改为调用b1。代码如下
@Service
public class AImpl implements A {
@Autowired
private B b;
@Autowired
private UserMapper userMapper;
@Transactional
@Override
public void a1() {
userMapper.insert(1,"user1");
try {
b.b1();
}catch (Exception e){
e.printStackTrace();
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void a2() {
userMapper.insert(2,"user2");
throw new RuntimeException("抛个可爱的异常!");
}
}
@Service
public class BImpl implements B {
@Autowired
private UserMapper userMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void b1() {
userMapper.insert(2,"user2");
throw new RuntimeException("抛个可爱的异常!");
}
@Transactional
@Override
public void b2() {
//
}
}
此次,运行结果正常,的确只插入了user1。运行结果如图3所示。
所以,在同一个service中使用requires_new,内层方法并不会开启新的事务,就像required一样。
如果在同一个service类中定义的两个方法, 内层REQUIRES_NEW并不会开启新的事务,save和update中回滚都会导致整个事务的回滚
如果在不同的service中定义的两个方法, 内层REQUIRES_NEW会开启新的事务,并且二者独立,事务回滚互不影响
总结
对于requires_new,在同一个service里面两个方法的调用,内层方法并不会开启新的事务,就行required一样。而不同service的两个方法的调用,内层方法总是会开启一个新的事务。
参考文献
Spring编程:Spring事务的传播特性和隔离级别
Creating and Configuring an Oracle Database
Oracle中如何创建数据库