一、什么是spring事务传播行为?
事务的传播行为就是在一个方法中嵌套一个或者多个事务,这个(些)嵌套的事务就涉及到了事务的传播行为,对于事务传播行为类型的设置是在被调用的方法上进行。例如:
public void methodParentA() {
methodA();
methodB();
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodParentB() {
methodA();
methodB();
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
System.out.println("methodA");
}
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() {
System.out.println("methodB");
}
如上代码,无论是在methodParentA还是在methodParentB中,都涉及到了事务的传播行为,其中propagation设置的类型不一样,会是不同的事务传播行为。
二、七种事务传播行为
在spring中有七种事务传播行为类型,分别是
PROPAGATION_REQUIRED | 如果一个事务已开启,使用当前事务;如果没有事务开启,则开启自己的事务 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY | 使用当前事务,如果没有当前事务则抛出异常 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行,如果当前存在事务,将当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,在嵌套事务内执行;如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作 |
三、以PROPAGATION_REQUIRED类型为例详解事务传播行为
1.在这里用到了两张测试表,两张表结构完全一样,仅名字不同。
CREATE TABLE `animal1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `animal2` (
`id` int(11) NOT NULL DEFAULT '0',
`name` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id`)
)
2.两张表所对应的各自的业务层代码
@Service
public class Animal1ServiceImpl implements Animal1Service {
@Autowired
private Animal1Mapper animal1Mapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void add(Animal1 animal1) {
animal1Mapper.insert(animal1);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addWithException(Animal1 animal1) {
animal1Mapper.insert(animal1);
throw new RuntimeException();
}
}
@Service
public class Animal2ServiceImpl implements Animal2Service {
@Autowired
private Animal2Mapper animal2Mapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void add(Animal2 animal2) {
animal2Mapper.insert(animal2);
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void addWithException(Animal2 animal2) {
animal2Mapper.insert(animal2);
throw new RuntimeException();
}
}
3.以PROPAGATION_REQUIRED类型为例,在五种种情况下分别测试,并记录测试结果
/**
* 1.外层没有开启事务,但最后一行抛出异常
* 2.内层两个事务传播行为均为REQURED,其中一个有抛出异常
* 3.结果为animal1表插入了“狮子1”,animal2表未插入成功
*/
public void testRequiredNoTransactionalThrowException() {
Animal1 animal1 = new Animal1();
animal1.setName("狮子1");
animal1Service.add(animal1);
Animal2 animal2 = new Animal2();
animal2.setName("狮子2");
animal2Service.addWithException(animal2);
throw new RuntimeException();
}
/**
* 1.外层没有开启事务,且没有抛出异常
* 2.内层两个事务传播行为均为REQURED,其中一个有抛出异常
* 3.结果为animal1表插入了“狮子1”,animal2表未插入成功
*/
@Override
public void testRequiredNoTransactional() {
Animal1 animal1 = new Animal1();
animal1.setName("狮子1");
animal1Service.add(animal1);
Animal2 animal2 = new Animal2();
animal2.setName("狮子2");
animal2Service.addWithException(animal2);
}
/**
* 1.外层开启事务,且没有抛出异常
* 2.内层两个事务传播行为均为REQURED,其中一个有抛出异常
* 3.结果为内层两个事务都发生了回滚,没有插入成功
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testRequiredTransactional() {
Animal1 animal1 = new Animal1();
animal1.setName("狮子1");
animal1Service.add(animal1);
Animal2 animal2 = new Animal2();
animal2.setName("狮子2");
animal2Service.addWithException(animal2);
}
/**
* 1.外层开启事务,且抛出异常
* 2.内层两个事务传播行为均为REQURED,且都正常执行
* 3.结果为内层两个事务都发生了回滚,没有插入成功
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testRequiredTransactionalThrowException() {
Animal1 animal1 = new Animal1();
animal1.setName("狮子1");
animal1Service.add(animal1);
Animal2 animal2 = new Animal2();
animal2.setName("狮子2");
animal2Service.add(animal2);
throw new RuntimeException();
}
/**
* 1.内层两个事务传播行为均为REQURED,其中一个有抛出异常
* 2.外层捕获异常,不主动抛出异常
* 3.结果为内层两个事务都发生了回滚,没有插入成功
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void testRequiredTransactionalTryException() {
Animal1 animal1 = new Animal1();
animal1.setName("狮子1");
animal1Service.add(animal1);
Animal2 animal2 = new Animal2();
animal2.setName("狮子2");
try {
animal2Service.addWithException(animal2);
} catch (Exception e) {
System.out.println("捕获异常,回滚");
}
}
4.结论
(1)在外层方法中没有开启事务的情况下,内层事务传播类型为 Propagation.REQUIRED的事务会各自开启新的事务,并且相互之间独立,互不干扰;
(2)在外层方法中开启事务的情况下,在内层事务传播类型为Propagation.REQUIRED的事务会加入外层的事务,也就是它们同属于一个事务,只要有其中一个逻辑发生了回滚,则外层方法所包含的内容全部回滚。
5.其他
在这里,我以事务传播类型Propagation.REQUIRED为例,测试了七种事务传播类型中的一种。本文的目的主要是在解释spring的事务传播类型是什么,而其他六种事务传播类型的测试结果就不在此赘述了。