前言

  • Spring @Transactional 的注解在日常开发中经常用到,日常都是通过这种形式@Transactional(rollbackFor = Exception.class)来使用,如果遇到一个事务方法内部调用了另一个事务方法,这种情况Spring事务是如何处理的呢?所以就有了事务传播的处理

  • 针对上面这种情况,Spring定义了7种事务传播行为:

1
2
3
4
5
6
7
REQUIRED
SUPPORTS
MANDATORY
REQUIRES_NEW
NOT_SUPPORTED
NEVER
NESTED
  • 源码定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public enum Propagation {

/**
* Support a current transaction, create a new one if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>This is the default setting of a transaction annotation.
*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

/**
* Support a current transaction, execute non-transactionally if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: For transaction managers with transaction synchronization,
* PROPAGATION_SUPPORTS is slightly different from no transaction at all,
* as it defines a transaction scope that synchronization will apply for.
* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
* will be shared for the entire specified scope. Note that this depends on
* the actual synchronization configuration of the transaction manager.
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

/**
* Support a current transaction, throw an exception if none exists.
* Analogous to EJB transaction attribute of the same name.
*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

/**
* Create a new transaction, and suspend the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

/**
* Execute non-transactionally, suspend the current transaction if one exists.
* Analogous to EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available it to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

/**
* Execute non-transactionally, throw an exception if a transaction exists.
* Analogous to EJB transaction attribute of the same name.
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),

/**
* Execute within a nested transaction if a current transaction exists,
* behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB.
* <p>Note: Actual creation of a nested transaction will only work on specific
* transaction managers. Out of the box, this only applies to the JDBC
* DataSourceTransactionManager when working on a JDBC 3.0 driver.
* Some JTA providers might support nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);


private final int value;


Propagation(int value) { this.value = value; }

public int value() { return this.value; }

}
  • @Transactional 的注解使用的是默认的事务传播形式 Propagation propagation() default Propagation.REQUIRED

实例

  • 现在通过实际例子来看下这些场景,毕竟实践才是检验真理的唯一标准,我们先准备下

  • sys_user

1
2
3
4
5
6
7
8
9
10
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`username` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
`password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
`age` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;
  • Mybatis定义
1
2
3
4
5
public interface UserMapper {

int insertSelective (IUser iUser);

}
1
2
3
4
5
6
7
8
9
10
11
@Data
public class IUser {

private Integer id;

private String username;

private String password;

private Integer age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<insert id="insertSelective" parameterType="org.springframework.iframe.entity.IUser">
insert into sys_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="username != null">
username,
</if>
<if test="password != null">
password,
</if>
<if test="age != null">
age,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="username != null">
#{username,jdbcType=VARCHAR},
</if>
<if test="password != null">
#{password,jdbcType=VARCHAR},
</if>
<if test="age != null">
#{age,jdbcType=INTEGER},
</if>
</trim>
</insert>

REQUIRED

  • 此模式是 @Transactional 的注解的默认的事务传播形式,此模式是如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

场景一:

  • 测试外层方法没有加事务注解的情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Service
public class UserService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserService userService;

public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
userService.insertByException(iUser2);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 测试类
1
2
3
4
5
6
7
8
9
10
11
12
@Slf4j
public class UserServiceTest {

private final ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("beans/applicationContext.xml");

@Test
public void test1() throws Exception {
UserService userService = xmlApplicationContext.getBean(UserService.class);
userService.insertAll();
}

}
  • 结果:
  • 运行分析
    • insertAll()外层方法没有加@Transactionalinsert(IUser user)方法和insertByException(IUser user)都加了事务注解
    • 从上面结果可以看到里层方法都是在自己的事务里运行的,第一个方法插入成功,第二个方法插入失败

场景二:

  • 测试外层方法加了事务注解的情况,删除上面新增的sql数据,然后在insertAll()外层方法加@Transactional注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Service
public class UserService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserService userService;

@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
userService.insertByException(iUser2);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 结果:
  • 运行分析
    • 可以看到是都没有插入成功,就是里层的事务是和外层的事务绑在一起了

场景三:

  • 下面这种场景是userService.insertByException(iUser2)代码块被catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Slf4j
@Service
public class UserService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserService userService;

@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

try {
IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
userService.insertByException(iUser2);
} catch (Exception e) {
log.error("回滚拉", e);
}
}

@Transactional(propagation = Propagation.REQUIRED)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 结果:
  • 运行分析
    • 可以看到里层事务方法将异常抛出来如果在外层方法里将调用方法catch住,也会触发回滚

REQUIRES_NEW

  • 这种模式下方法会自己独立开启自己的事务(自己new),不会像REQUIRED模式那样加入到外层事务中,所以外层方法事务和里层方法事务是独立的,互不干扰
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Slf4j
@Service
public class UserRequiresNewService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserRequiresNewService userRequiresNewService;

@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userRequiresNewService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
try {
userRequiresNewService.insertByException(iUser2);
} catch (Exception e) {
log.error("回滚拉", e);
}
IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userRequiresNewService.insert(iUser3);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 结果:
  • 运行分析
    • 可以看到外层方法事务和里层方法事务是独立的,互不干扰

NESTED

  • 这种是嵌套事务,外层方法事务会影响里层嵌套事务

场景一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Slf4j
@Service
public class UserRequiresNestedService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserRequiresNestedService userRequiresNewService;

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userRequiresNewService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
try {
userRequiresNewService.insertByException(iUser2);
} catch (Exception e) {
log.error("回滚拉", e);
}
IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userRequiresNewService.insert(iUser3);
throw new NullPointerException();
}

@Transactional(propagation = Propagation.NESTED)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.NESTED)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 结果:
  • 运行分析
    • 可以看到外层方法抛出了一个空指针异常,导致里层方法也没有插入成功,就是说外层方法事务会影响里层嵌套事务

场景二

  • 把上面那种场景将外层方法的空指针异常去掉
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void insertAll1() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
try {
userService.insertByException(iUser2);
} catch (Exception e) {
log.error("回滚拉", e);
}
IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userService.insert(iUser3);
}

@Transactional(propagation = Propagation.NESTED)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.NESTED)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}
  • 结果:
  • 运行分析
    • 可以看到插入了两条语句

NEVER

  • 以非事务方式执行,如果当前存在事务,则抛出异常

场景一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Slf4j
@Service
public class UserRequiresNeverService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserRequiresNeverService userService;

@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userService.insert(iUser3);
}

@Transactional(propagation = Propagation.NEVER)
public void insert(IUser user){
userMapper.insertSelective(user);
}

}
  • 结果:
1
2
3
4
5
6
7
8
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

at org.springframework.transaction.support.AbstractPlatformTransactionManager.handleExistingTransaction(AbstractPlatformTransactionManager.java:414)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:351)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:459)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:183)
  • 运行分析
    • 可以看到直接抛异常了

MANDATORY

  • 使用当前的事务,如果当前没有事务,就抛出异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Slf4j
@Service
public class UserRequiresMandatoryService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserRequiresMandatoryService userService;

//@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userService.insert(iUser3);
}

@Transactional(propagation = Propagation.MANDATORY)
public void insert(IUser user){
userMapper.insertSelective(user);
}
}
  • 结果:
1
2
3
4
5
6
7
8
9
10

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:363)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:459)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:677)
at org.springframework.iframe.test.transaction.v1.UserRequiresMandatoryService$$EnhancerBySpringCGLIB$$4b2b881a.insert(<generated>)
  • 运行分析
    • 可以看到直接抛异常了

SUPPORTS

  • 支持当前事务,如果当前没有事务,就以非事务方式执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Slf4j
@Service
public class UserRequiresSupportsService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserRequiresSupportsService userService;

@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
try {
userService.insertByException(iUser2);
} catch (Exception e) {
log.error("回滚拉", e);
}
IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userService.insert(iUser3);
}

@Transactional(propagation = Propagation.SUPPORTS)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.SUPPORTS)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:735)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:301)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:677)
at org.springframework.iframe.test.transaction.v1.UserRequiresSupportsService$$EnhancerBySpringCGLIB$$2a6bf39.insertAll(<generated>)
at org.springframework.iframe.test.transaction.UserRequiredServiceTest.test7(UserRequiredServiceTest.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
  • 运行分析
    • 可以看到是直接回滚了,和REQUIRED区别的话就是不会另外新开事务

NOT_SUPPORTED

  • 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Slf4j
@Service
public class UserRequiresNotSupportsService {

@Autowired
private UserMapper userMapper;

@Autowired
private UserRequiresNotSupportsService userService;

@Transactional(propagation = Propagation.REQUIRED)
public void insertAll() {
IUser iUser1 = new IUser();
iUser1.setUsername("小宋1");
userService.insert(iUser1);

IUser iUser2 = new IUser();
iUser2.setUsername("小宋2");
try {
userService.insertByException(iUser2);
} catch (Exception e) {
log.error("回滚拉", e);
}
IUser iUser3 = new IUser();
iUser3.setUsername("小宋3");
userService.insert(iUser3);
}

@Transactional(propagation = Propagation.REQUIRED)
public void insert(IUser user){
userMapper.insertSelective(user);
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void insertByException(IUser user){
userMapper.insertSelective(user);
throw new RuntimeException();
}

}
  • 结果
  • 运行分析
    • 可以看到insertByException()是没有开启事务,数据都插入进去了

总结

  • Spring定义了7种事务传播行为供我们选择,我们可以根据实际业务场景自定义

REQUIRED 一条绳上的蚂蚱

  • 意思是必须,必须在事务环境中,如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中,这种是默认的传播策略

  • 外层事务方法如果调用了其他事务方法,里层方法就会加入到这个外层方法的事务中去,如果里层方法抛出了异常会影响到整个事务

  • 外层非事务方法如果调用了其他事务方法,当前没有事务那么这个里层方法会自己新开事务

REQUIRES_NEW 另起炉灶

  • 这种是新建一个事务,管你有没有,都自己搞,里层事务和外层事务独立互不干扰

  • 如果有一个现有事务正在运行的话,则它将在当前方法运行期间被挂起

NESTED 国与省的关系

  • 这种是嵌套事务
  • 里层事务可以独立回滚
  • 因为是嵌入模式所以会受到外层方法事务的影响,如果外层方法抛出了异常会影响到里层方法事务

NEVER 不能有,拒绝

  • 以非事务方式执行,如果当前有事务,则抛出异常

MANDATORY 不能没有,强制

  • 意思是强制,表示该方法必须运行在一个事务中,会使用当前的事务,如果当前没有事务,就抛出异常

SUPPORTS 墙头草

  • 支持当前事务,如果当前没有事务,就以非事务方式执行

  • 和REQUIRED区别的话就是不会另外新开事务

NOT_SUPPORTED 无所谓

  • 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起

  • 和NEVER区别就是不会抛异常