Spring特有的事务传播行为,Spring支持7种事务传播行为,确定客户端和被调用端的事务边界。即多个具有事务控制的service进行相互调用时所参生的复杂行为。下面对7种进行合理的分析和讲解。
事务传播行为 | 含义 |
PROPAGATION_REQUIRED | 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置 |
PROPAGATION_REQUIRED_NEW | 创建新事务,无论当前存不存在事务,都创建新事务 |
PROPAGATION_MANDATORY | 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行 |
PROPAGATION_NOT_SUPPORTED | 以非事务的方式执行,如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
下面我将举例对这七种行为进行复现。并根据结果进行分析。
环境:Spring-boot + Mysql
创建实例类 Admin :
public class Admin {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String password;
@Enumerated(EnumType.STRING)
private AdminType type;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public AdminType getType() {
return type;
}
public void setType(AdminType type) {
this.type = type;
}
}
1. PROPAGATION_REQUIRED
创建事务function和,事务的测试function
@Transactional(propagation = Propagation.REQUIRED)
public void transactionTest(){
Admin admin=new Admin();
admin.setType(AdminType.管理员);
admin.setName("test");
admin.setPassword("123");
adminRepository.save(admin);
throw new RuntimeException("error");
}
@Test
public void testTransaction(){
adminService.transactionTest();
}
执行testTransaction函数。发现抛出异常,数据里面没有添加新的数据。证明按照了事务的方式在执行函数。
2.PROPAGATION_REQUIRED_NEW
修改transactionTest 和 testTransaction函数如下
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void transactionTest(){
Admin admin=new Admin();
admin.setType(AdminType.管理员);
admin.setName("test");
admin.setPassword("123");
adminRepository.save(admin);
}
@Test
@Transactional()
public void testTransaction(){
adminService.transactionTest();
throw new RuntimeException("Error");
}
在testTransaction函数里面抛出异常。结果是数据库正常的存入数据了。证明是transactionTest函数又自己创建了一个事务。与外层的事务没有关系。外层事务的回滚不影响到内层事务的正常执行。
3.PROPAGATION_MANDATORY
修改transactionTest和testTransaction函数如下:
@Transactional(propagation = Propagation.MANDATORY) public void transactionTest(){ Admin admin=new Admin(); admin.setType(AdminType.管理员); admin.setName("test"); admin.setPassword("123"); adminRepository.save(admin); }
@Test public void testTransaction(){ adminService.transactionTest(); throw new RuntimeException("Error"); }
运行直接抛出异常如下:
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
表面Mandatory必须要存在事务才能调用,不然就直接抛出异常。
4.PROPAGATION_SUPPORTS
修改函数如下:
@Test public void testTransaction(){ adminService.transactionTest(); }
@Transactional(propagation = Propagation.SUPPORTS) public void transactionTest(){ Admin admin=new Admin(); admin.setType(AdminType.管理员); admin.setName("test"); admin.setPassword("123"); adminRepository.save(admin); throw new RuntimeException("Error"); }
执行结果,抛出异常,但是数据还是存储到了数据库。说明在调用方没有事务的情况下,按照没有事务执行。
5.PROPAGATION_NOT_SUPPORTED
修改函数如下:
@Test @Transactional public void testTransaction(){ adminService.transactionTest(); }
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void transactionTest(){ Admin admin=new Admin(); admin.setType(AdminType.管理员); admin.setName("test"); admin.setPassword("123"); adminRepository.save(admin); throw new RuntimeException("Error"); }
运行结果如下,抛出异常。数据存入到数据库。说明调用方就算是有事务,被调用方依旧按照非事务的方式在执行。
6.PROPAGATION_NEVER
@Test @Transactional public void testTransaction(){ adminService.transactionTest(); }
@Transactional(propagation = Propagation.NEVER) public void transactionTest(){ Admin admin=new Admin(); admin.setType(AdminType.管理员); admin.setName("test"); admin.setPassword("123"); adminRepository.save(admin); }直接排除异常,不支持事务。
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
7.PROPAGATION_NESTED
修改函数如下:
@Test @Transactional public void testTransaction(){ adminService.transactionTest(); }
@Transactional(propagation = Propagation.NESTED) public void transactionTest(){ Admin admin=new Admin(); admin.setType(AdminType.管理员); admin.setName("test"); admin.setPassword("123"); adminRepository.save(admin); throw new RuntimeException("Error"); }
运行结果:抛出异常,数据没有存入到数据库。证明是按照事务的方式进行执行的。