只要涉及到数据库操作,必定就会使用 @Transactional
注解,其中有一个属性就是 propagation(传播类型),掌握它的用法很重要。演示代码见末尾。
演示事务传播
基础代码
定义了所有的传播类型,第二个参数来控制是否抛出异常。
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
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED(User user, boolean throwException) {
insertUser(user, throwException);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void REQUIRES_NEW(User user, boolean throwException) {
insertUser(user, throwException);
}
@Transactional(propagation = Propagation.NESTED)
public void NESTED(User user, boolean throwException) {
insertUser(user, throwException);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void NOT_SUPPORTED(User user, boolean throwException) {
insertUser(user, throwException);
}
@Transactional(propagation = Propagation.SUPPORTS)
public void SUPPORTS(User user, boolean throwException) {
insertUser(user, throwException);
}
@Transactional(propagation = Propagation.NEVER)
public void NEVER(User user, boolean throwException) {
insertUser(user, throwException);
}
@Transactional(propagation = Propagation.MANDATORY)
public void MANDATORY(User user, boolean throwException) {
insertUser(user, throwException);
}
|
REQUIRED_REQUIRED
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_REQUIRED() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.REQUIRED(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:不会插入数据, 会抛出异常
分析:第一次调用创建新的事务状态,第二次调用因为是 REQUIRED
, 所以会共用之前的事务状态,这样两次调用是同一个事务状态。
第二次调用发生异常,事务状态要回滚,而第一次调用没有异常,事务状态要提交,导致事务状态冲突。
REQUIRED_REQUIRES_NEW
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_REQUIRES_NEW() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.REQUIRES_NEW(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:会插入 111 数据
分析:第一次调用创建新的事务状态,第二次调用因为是 REQUIRES_NEW
, 所以会创建新的事务状态,这样两次调用不是同一个事务状态。
第二次调用发生异常,事务状态要回滚,而第一次调用没有异常,事务状态要提交。
REQUIRED_NESTED
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_NESTED() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.NESTED(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:会插入 111 数据
分析:第一次调用创建新的事务状态,第二次调用因为是 NESTED
, 所以会设置保存点,这样两次调用是同一个事务状态。
第二次调用发生异常,事务状态要回滚到保存点,而第一次调用没有异常,事务状态要提交。
REQUIRED_NOT_SUPPORTED
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_NOT_SUPPORTED() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.NOT_SUPPORTED(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:会插入 111 数据, 222 数据
分析:第一次调用创建新的事务状态,第二次调用因为是 NOT_SUPPORTED
, 所以会挂起事务,这样只有第一次调用是有事务。
第二次调用发生异常,因为没有事务,所以不会回滚,而第一次调用没有异常,事务状态要提交。
REQUIRED_SUPPORTS
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_SUPPORTS() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.SUPPORTS(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:不会插入数据, 会抛出异常
分析:第一次调用创建新的事务状态,第二次调用因为是 SUPPORTS
, 所以会共用之前的事务状态,这样两次调用是同一个事务状态。
第二次调用发生异常,事务状态要回滚,而第一次调用没有异常,事务状态要提交,导致事务状态冲突。
REQUIRED_NEVER
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_NEVER() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.NEVER(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:会插入 111 数据
分析:第一次调用创建新的事务状态,第二次调用因为是 NEVER
, 所以会抛出异常不会继续执行代码。
第一次调用没有异常,事务状态要提交。
REQUIRED_MANDATORY
1
2
3
4
5
6
7
8
| @Transactional(propagation = Propagation.REQUIRED)
public void REQUIRED_MANDATORY() {
serviceA.REQUIRED(new User("111"), false);
try {
serviceA.MANDATORY(new User("222"), true);
} catch (Exception ignored) {
}
}
|
结论:不会插入数据, 会抛出异常
分析:第一次调用创建新的事务状态,第二次调用因为是 REQUIRED
, 所以会共用之前的事务状态,这样两次调用是同一个事务状态。
第二次调用发生异常,事务状态要回滚,而第一次调用没有异常,事务状态要提交,导致事务状态冲突。
事务传播原理
源码位置: org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
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
| // 每一个 @Transactional 都会执行下面的方法,来获取事务状态
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
...
// 获取当前事务
Object transaction = doGetTransaction();
// 判断事务是否存在
if (isExistingTransaction(transaction)) {
// 重点解析
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 下面是不存在事务的情况
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
...
try {
// 开启新的事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
...
// 不开始事务
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
|
源码位置: org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
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
| private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 下面是存在事务的情况
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
...
// 挂起当前事务,以非事务来执行
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
...
// 挂起当前事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 开启新事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
...
if (useSavepointForNestedTransaction()) {
...
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 在当前事务上,创建保存点
status.createAndHoldSavepoint();
return status;
}
else {
// 不支持保存点,就开启新事务
return startTransaction(definition, transaction, debugEnabled, null);
}
}
...
// 继续使用当前事务
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
|
说明:在 startTransaction
方法中,每次都会获取新连接来开启事务。
代码
demo-spring-transaction-propagation