# @Transactional事务异步失效
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.context.annotation.Bean;
/**
* 业务服务类
* 演示如何正确实现异步事务处理
*/
@Service
public class BusinessService {
/**
* 注入ApplicationContext用于获取代理对象
* 解决自调用导致的事务失效问题
*/
@Autowired
private ApplicationContext applicationContext;
/**
* 主业务处理方法 - 使用声明式事务
*
* 事务传播机制:REQUIRED(默认)
* - 如果当前没有事务,则新建一个事务
* - 如果当前存在事务,则加入该事务
*/
@Transactional
public void mainProcess() {
// 同步操作 - 在主事务中执行
// 这部分操作会立即执行,并且与主方法在同一个事务上下文中
// 如果此处发生异常,整个事务会回滚
System.out.println("主事务ID: " + TransactionSynchronizationManager.getCurrentTransactionName());
syncOperation();
// 异步操作 - 启动独立的事务
// 方案1:通过代理对象调用(推荐)
BusinessService proxy = applicationContext.getBean(BusinessService.class);
CompletableFuture.runAsync(() -> {
try {
// 通过代理对象调用,确保事务生效
proxy.asyncOperation();
} catch (Exception e) {
// 异步操作的异常处理
// 记录日志,但不要影响主流程
System.err.println("异步操作失败: " + e.getMessage());
// 可能的补偿措施
compensateAsyncFailure();
}
});
// 方案2:使用Spring的@Async注解(需要开启@EnableAsync)
// proxy.asyncOperationWithAsync();
// 主方法可以继续执行其他操作,无需等待异步任务完成
// 主事务的提交与异步操作的事务相互独立
System.out.println("主方法继续执行其他操作...");
}
/**
* 同步操作方法
* 在主事务中执行
*/
private void syncOperation() {
System.out.println("执行同步操作,事务ID: " +
TransactionSynchronizationManager.getCurrentTransactionName());
// 这里是同步的业务逻辑
// 如果这里抛出异常,整个主事务会回滚
}
/**
* 异步操作方法 - 使用独立的新事务
*
* 事务传播机制:REQUIRES_NEW
* - 总是新建一个独立的事务
* - 如果当前存在事务,则挂起当前事务
*
* 重要:必须通过代理对象调用此方法,事务才会生效
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void asyncOperation() {
System.out.println("异步操作开始,新事务ID: " +
TransactionSynchronizationManager.getCurrentTransactionName());
try {
// 这里是异步的业务逻辑
// 例如:记录日志、发送通知等
// 模拟业务操作
System.out.println("执行异步业务逻辑...");
// 如果这里抛出异常,只会回滚当前独立事务
// 不会影响主事务
} catch (Exception e) {
// 在独立事务中处理异常
// 可以选择记录日志后重新抛出,或者吞掉异常
System.err.println("异步操作内部异常: " + e.getMessage());
throw e; // 抛出异常会导致当前独立事务回滚
}
System.out.println("异步操作完成");
}
/**
* 方法2:使用Spring的@Async注解实现异步事务
* 需要配合@EnableAsync使用
*
* 优点:更简洁,Spring自动管理线程池
* 缺点:需要在启动类添加@EnableAsync
*/
@Async("asyncTaskExecutor")
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void asyncOperationWithAsync() {
System.out.println("@Async异步操作,线程: " + Thread.currentThread().getName());
System.out.println("事务ID: " + TransactionSynchronizationManager.getCurrentTransactionName());
// 异步业务逻辑
System.out.println("执行@Async异步操作...");
}
/**
* 异步操作失败补偿方法
*/
private void compensateAsyncFailure() {
System.out.println("执行异步操作失败补偿逻辑...");
// 例如:记录失败信息到数据库、发送告警等
}
/**
* 方法3:使用事务同步器在主事务提交后执行异步操作
* 确保主事务成功后才执行异步操作
*/
@Transactional
public void mainProcessWithAfterCommit() {
syncOperation();
BusinessService proxy = applicationContext.getBean(BusinessService.class);
// 注册事务同步器,在主事务提交成功后执行
TransactionSynchronizationManager.registerSynchronization(
new org.springframework.transaction.support.TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 主事务提交成功后执行异步操作
CompletableFuture.runAsync(() -> {
proxy.asyncOperation();
});
}
}
);
System.out.println("主事务执行完成,等待提交后执行异步操作");
}
}
/**
* 线程池配置类
* 为异步操作提供专用的线程池
*/
@Configuration
@EnableAsync // 启用Spring的异步支持
class AsyncConfig {
/**
* 自定义异步任务线程池
* 避免使用默认的ForkJoinPool,提供更好的控制
*/
@Bean("asyncTaskExecutor")
public Executor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(5);
// 最大线程数
executor.setMaxPoolSize(10);
// 队列容量
executor.setQueueCapacity(100);
// 线程名前缀
executor.setThreadNamePrefix("async-transaction-");
// 拒绝策略:调用者运行(由调用线程执行任务)
executor.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
// 线程空闲时间
executor.setKeepAliveSeconds(60);
// 等待所有任务完成后关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
/**
* 启动类配置
*/
@SpringBootApplication
@EnableAsync // 启用异步支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
/**
* 使用示例
*/
@Service
class ExampleService {
@Autowired
private BusinessService businessService;
public void executeExample() {
// 方案1:直接调用(推荐)
businessService.mainProcess();
// 方案2:使用事务同步器
// businessService.mainProcessWithAfterCommit();
}
}
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# 1. 解决事务失效的核心方法
// ❌ 错误:自调用,事务失效
CompletableFuture.runAsync(() -> this.asyncOperation());
// ✅ 正确:通过代理对象调用
BusinessService proxy = applicationContext.getBean(BusinessService.class);
CompletableFuture.runAsync(() -> proxy.asyncOperation());
1
2
3
4
5
6
2
3
4
5
6
# 2. 三种异步事务实现方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 代理对象+CompletableFuture | 灵活可控,无需额外配置 | 需要手动获取代理对象 | 简单的异步任务 |
| @Async注解 | 简洁,Spring自动管理 | 需要@EnableAsync配置 | 标准异步任务 |
| 事务同步器 | 确保主事务成功后执行 | 代码稍复杂 | 依赖主事务结果的场景 |
# 3. 最佳实践建议
- 异常处理:异步操作内部要处理异常,避免影响主流程
- 线程池配置:使用自定义线程池,避免线程资源竞争
- 事务监控:添加事务ID日志,便于问题排查
- 资源清理:确保异步操作中的资源正确释放
- 超时控制:为异步操作设置合理的超时时间
这个完整方案解决了异步事务失效的问题,并提供了多种实现方式供选择。