概述

Spring事务钩子是一套强大的机制,这些钩子提供了对事务管理的细粒度控制,允许开发者在事务生命周期的不同阶段执行自定义逻辑。

主要的事务钩子类型

1. TransactionSynchronization(事务同步器)

TransactionSynchronization是最核心的事务钩子接口,提供了以下回调方法:

核心方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface TransactionSynchronization {
// 事务状态常量
int STATUS_COMMITTED = 0; // 已提交
int STATUS_ROLLED_BACK = 1; // 已回滚
int STATUS_UNKNOWN = 2; // 状态未知

// 事务挂起时调用
void suspend();

// 事务恢复时调用
void resume();

// 事务刷新时调用(在提交前)
void flush();

// 事务提交前调用
void beforeCommit(boolean readOnly);

// 事务提交后调用
void beforeCompletion();

// 事务完成后调用
void afterCompletion(int status);
}

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component
public class OrderTransactionSynchronization implements TransactionSynchronization {

@Override
public void beforeCommit(boolean readOnly) {
// 事务提交前的准备工作
logger.info("准备提交事务");
}

@Override
public void afterCompletion(int status) {
if (status == STATUS_COMMITTED) {
// 事务提交成功后的处理
logger.info("事务提交成功");
} else if (status == STATUS_ROLLED_BACK) {
// 事务回滚后的处理
logger.warn("事务回滚");
}
}
}

2. TransactionalEventListener(事务事件监听器)

Spring 4.2+引入了@TransactionalEventListener注解,允许在事务的不同阶段监听事件:

事务阶段

  • BEFORE_COMMIT: 事务提交前
  • AFTER_COMMIT: 事务提交后
  • AFTER_ROLLBACK: 事务回滚后
  • AFTER_COMPLETION: 事务完成后(无论提交还是回滚)

TransactionalEventListener的使用

1. 钩子注册(订单创建示例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 在订单创建事务方法中注册钩子
@Transactional
public OrderResponse createOrder(OrderRequest request) {
String orderId = generateOrderId();

// 注册事务同步钩子
OrderTransactionSynchronization.registerSynchronization(orderId, "CREATE_ORDER");

// 业务逻辑:验证用户、库存、扣减余额等...

// 发布订单创建事件
// 如果在事件发送之前出现异常,那么事务监听器就得不到执行了,所以这个用起来没有事务同步器那么灵活
eventPublisher.publishEvent(new OrderCreatedEvent(order));

return OrderResponse.success(order, productName, "订单创建成功");
}
2. 异步审计日志
1
2
3
4
5
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void auditOrderCreation(OrderCreatedEvent event) {
// 记录审计日志
auditService.logOrderCreation(event.getOrder());
}
2. 异步缓存更新
1
2
3
4
5
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void updateCache(OrderCreatedEvent event) {
// 更新缓存
cacheService.evictUserOrders(event.getUserId());
}
3. 异步消息通知
1
2
3
4
5
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendNotification(OrderCreatedEvent event) {
// 发送消息通知
notificationService.sendOrderConfirmation(event.getOrder());
}
4. 异步补偿操作
1
2
3
4
5
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleOrderFailure(OrderCreatedEvent event) {
// 执行补偿操作
compensationService.handleOrderFailure(event.getOrder());
}

注意事项

1. 性能考虑

  • 同步事务器的钩子会在每个事务中执行,会阻塞事务线程的进行,避免在钩子中执行耗时操作
  • 考虑使用异步处理(线程池)或者事务监听器的方式来避免阻塞事务

2. 异常处理

  • 需要在钩子中妥善处理异常,否则会影响正常事务的执行

3. 事务传播

  • 钩子只在当前事务中生效
  • 新事务不会继承父事务的钩子

核心类:TransactionSynchronizationManager

TransactionSynchronizationManager是Spring事务钩子的核心管理类,负责管理事务同步钩子的注册、执行和清理。

核心原理

TransactionSynchronizationManager使用ThreadLocal来存储当前线程的事务同步钩子,确保每个事务线程都有独立的钩子集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class TransactionSynchronizationManager {
// 使用ThreadLocal存储同步钩子
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");

// 使用ThreadLocal存储事务状态
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");

// 使用ThreadLocal存储当前事务名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
}

主要方法

1. 钩子注册和管理

1
2
3
4
5
6
7
8
9
10
11
// 检查是否有活跃的事务
public static boolean isSynchronizationActive()

// 注册事务同步钩子
public static void registerSynchronization(TransactionSynchronization synchronization)

// 获取所有注册的同步钩子
public static Set<TransactionSynchronization> getSynchronizations()

// 清除所有同步钩子
public static void clearSynchronization()

2. 事务状态管理

1
2
3
4
5
6
7
8
9
10
11
// 检查当前是否有活跃事务
public static boolean isActualTransactionActive()

// 设置事务活跃状态
public static void setActualTransactionActive(boolean active)

// 获取当前事务名称
public static String getCurrentTransactionName()

// 设置当前事务名称
public static void setCurrentTransactionName(String name)

3. 资源绑定管理

1
2
3
4
5
6
7
8
9
10
11
// 绑定资源到当前事务
public static void bindResource(Object key, Object value)

// 获取绑定的资源
public static Object getResource(Object key)

// 解绑资源
public static Object unbindResource(Object key)

// 检查资源是否存在
public static boolean hasResource(Object key)

TransactionSynchronizationManager实际应用示例

1. 基础钩子注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class OrderService {

@Transactional
public OrderResponse createOrder(OrderRequest request) {
// 检查是否有活跃事务
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 注册自定义事务同步钩子
TransactionSynchronizationManager.registerSynchronization(
new OrderTransactionSynchronization(request.getOrderId(), "CREATE_ORDER")
);
}

// 业务逻辑...
return processOrder(request);
}
}

2. 资源绑定示例

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

@Transactional
public OrderResponse createOrder(OrderRequest request) {
String orderId = generateOrderId();

// 绑定订单ID到当前事务
TransactionSynchronizationManager.bindResource("orderId", orderId);

// 绑定用户信息到当前事务
TransactionSynchronizationManager.bindResource("userId", request.getUserId());

try {
// 业务逻辑处理
return processOrder(request);
} finally {
// 清理资源绑定
TransactionSynchronizationManager.unbindResource("orderId");
TransactionSynchronizationManager.unbindResource("userId");
}
}
}

3. 事务状态检查

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
@Component
public class OrderTransactionSynchronization implements TransactionSynchronization {

@Override
public void beforeCommit(boolean readOnly) {
// 检查事务状态
if (TransactionSynchronizationManager.isActualTransactionActive()) {
String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
logger.info("准备提交事务: {}", transactionName);
}
}

@Override
public void afterCompletion(int status) {
// 获取绑定的资源
String orderId = (String) TransactionSynchronizationManager.getResource("orderId");
Long userId = (Long) TransactionSynchronizationManager.getResource("userId");

if (status == STATUS_COMMITTED) {
logger.info("订单创建成功: orderId={}, userId={}", orderId, userId);
} else {
logger.warn("订单创建失败: orderId={}, userId={}", orderId, userId);
}
}
}