基于Spring Framework 6.x源码,深入剖析事务隔离级别和传播属性的设计原理与实际应用
在Spring框架的事务管理体系中,**隔离级别(Isolation Level)和传播属性(Propagation Behavior)**是两个核心概念,它们分别解决了不同维度的问题:
理解这两个概念的本质,有助于我们在复杂的业务场景中做出正确的事务配置选择。
在多事务并发执行的环境中,会出现以下经典问题:
问题描述: 一个事务读取了另一个事务未提交的数据
具体场景:
// 事务A
@Transactional
public void transferMoney() {
account.setBalance(1000); // 修改但未提交
// ... 其他操作
}
// 事务B
@Transactional
public void checkBalance() {
int balance = account.getBalance(); // 可能读到1000(脏数据)
// 如果事务A回滚,这个1000就是脏数据
}
问题描述: 同一事务中,两次读取同一数据得到不同结果
具体场景:
@Transactional
public void businessLogic() {
int balance1 = account.getBalance(); // 第一次读取:500
// 此时其他事务修改了balance并提交
int balance2 = account.getBalance(); // 第二次读取:1000
// balance1 != balance2,违反了事务的一致性
}
问题描述: 同一事务中,两次范围查询得到不同的记录数
具体场景:
@Transactional
public void statisticsAnalysis() {
List<Account> accounts1 = accountRepo.findByBalanceGreaterThan(500); // 查到3条
// 此时其他事务插入了新记录并提交
List<Account> accounts2 = accountRepo.findByBalanceGreaterThan(500); // 查到4条
// 出现了"幻影"记录
}
从Spring的TransactionDefinition
接口源码可以看出,隔离级别直接映射到JDBC标准:
// spring-tx/src/main/java/org/springframework/transaction/TransactionDefinition.java
public interface TransactionDefinition {
/**
* Use the default isolation level of the underlying datastore.
*/
int ISOLATION_DEFAULT = -1;
/**
* Indicates that dirty reads, non-repeatable reads, and phantom reads can occur.
* This level allows a row changed by one transaction to be read by another
* transaction before any changes in that row have been committed (a "dirty read").
*/
int ISOLATION_READ_UNCOMMITTED = 1;
/**
* Indicates that dirty reads are prevented; non-repeatable reads and
* phantom reads can occur.
*/
int ISOLATION_READ_COMMITTED = 2;
/**
* Indicates that dirty reads and non-repeatable reads are prevented;
* phantom reads can occur.
*/
int ISOLATION_REPEATABLE_READ = 4;
/**
* Indicates that dirty reads, non-repeatable reads, and phantom reads
* are prevented.
*/
int ISOLATION_SERIALIZABLE = 8;
}
隔离级别 | 脏读 | 不可重复读 | 幻读 | 解决的核心问题 |
---|---|---|---|---|
READ_UNCOMMITTED | ✅ 允许 | ✅ 允许 | ✅ 允许 | 无隔离,最高性能 |
READ_COMMITTED | ❌ 防止 | ✅ 允许 | ✅ 允许 | 防止读取脏数据 |
REPEATABLE_READ | ❌ 防止 | ❌ 防止 | ✅ 允许 | 保证读取一致性 |
SERIALIZABLE | ❌ 防止 | ❌ 防止 | ❌ 防止 | 完全串行化,最高一致性 |
Spring通过JDBC连接设置隔离级别,核心代码在DataSourceUtils
中:
// spring-jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java
public static Integer prepareConnectionForTransaction(Connection con, TransactionDefinition definition)
throws SQLException {
// 应用特定的隔离级别
Integer previousIsolationLevel = null;
if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
if (debugEnabled) {
logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " +
definition.getIsolationLevel());
}
int currentIsolation = con.getTransactionIsolation();
if (currentIsolation != definition.getIsolationLevel()) {
previousIsolationLevel = currentIsolation;
con.setTransactionIsolation(definition.getIsolationLevel()); // 核心调用
}
}
return previousIsolationLevel;
}
重要注意事项:
PROPAGATION_REQUIRED
、PROPAGATION_REQUIRES_NEW
、PROPAGATION_NESTED
有效传播属性主要解决以下三大类问题:
问题场景: 当一个事务方法调用另一个事务方法时,如何确定事务边界?
@Service
public class OrderService {
@Autowired
private PaymentService paymentService;
@Transactional
public void createOrder() {
// 创建订单逻辑
saveOrder();
// 调用支付服务 - 这里如何处理事务?
paymentService.processPayment();
}
}
@Service
public class PaymentService {
@Transactional // 这个事务如何与上层事务协调?
public void processPayment() {
// 支付处理逻辑
}
}
问题场景: 某些操作需要在独立的事务中执行,不受外层事务影响
@Transactional
public void businessOperation() {
// 主业务逻辑
performMainBusiness();
// 审计日志 - 即使主业务回滚,日志也要保存
auditService.logOperation(); // 需要独立事务
}
问题场景: 避免不必要的事务开销,优化数据库连接使用
@Transactional
public void expensiveOperation() {
// 大量计算逻辑,不需要数据库事务
performCalculation();
// 只有这部分需要事务
saveResult();
}
核心处理逻辑在AbstractPlatformTransactionManager.handleExistingTransaction()
方法中:
// spring-tx/src/main/java/org/springframework/transaction/support/AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// NEVER - 禁止在事务中执行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// NOT_SUPPORTED - 挂起当前事务,非事务执行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// REQUIRES_NEW - 挂起当前事务,创建新事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, false, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// NESTED - 创建嵌套事务(使用Savepoint)
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
if (useSavepointForNestedTransaction()) {
// 使用保存点创建嵌套事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, false, false, true, debugEnabled, null);
status.createAndHoldSavepoint();
return status;
}
else {
// JTA环境下的嵌套事务
return startTransaction(definition, transaction, true, debugEnabled, null);
}
}
// REQUIRED, SUPPORTS, MANDATORY - 加入现有事务
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
解决问题: 确保方法在事务中执行,是最常用的选择
@Transactional(propagation = Propagation.REQUIRED)
public void businessMethod() {
// 保证在事务中执行
// 有事务就加入,无事务就创建
}
源码行为:
解决问题: 需要独立事务执行,不受外层事务影响
@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void logOperation(String operation) {
// 即使外层事务回滚,审计日志也要保存
auditRepository.save(new AuditLog(operation));
}
}
@Service
public class OrderService {
@Transactional
public void createOrder() {
orderRepository.save(order);
// 记录审计日志 - 独立事务
auditService.logOperation("CREATE_ORDER");
if (someCondition) {
throw new RuntimeException("Order failed"); // 主事务回滚,但日志已保存
}
}
}
源码行为:
解决问题: 需要部分回滚能力的复杂业务场景
@Service
public class BatchProcessService {
@Transactional
public void processBatch(List<Item> items) {
for (Item item : items) {
try {
processItem(item); // 嵌套事务
} catch (Exception e) {
// 单个item处理失败,只回滚到savepoint
// 不影响其他item的处理
log.error("Item {} processing failed", item.getId(), e);
}
}
}
@Transactional(propagation = Propagation.NESTED)
private void processItem(Item item) {
// 在嵌套事务中处理单个item
// 失败时只回滚到savepoint
itemRepository.save(item);
updateStatistics(item);
}
}
源码行为:
解决问题: 可选事务执行,适用于查询操作
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public List<Order> findOrders(OrderQuery query) {
// 查询操作,有事务就加入,无事务也能执行
return orderRepository.findByQuery(query);
}
解决问题: 明确要求非事务执行,避免事务开销
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void expensiveCalculation() {
// 大量计算,不需要数据库事务
// 避免长时间占用数据库连接
performComplexCalculation();
}
解决问题: 强制要求在事务中执行,用于架构约束
@Transactional(propagation = Propagation.MANDATORY)
public void criticalOperation() {
// 这个方法必须在事务中调用
// 调用者必须提供事务上下文
}
解决问题: 禁止在事务中执行,用于特殊场景
@Transactional(propagation = Propagation.NEVER)
public void nonTransactionalOperation() {
// 绝对不能在事务中执行
// 比如某些外部API调用
}
@Service
public class OrderProcessService {
// 主业务流程 - 使用默认REQUIRED
@Transactional(
isolation = Isolation.READ_COMMITTED, // 防止脏读
propagation = Propagation.REQUIRED
)
public void processOrder(OrderRequest request) {
// 1. 创建订单
Order order = createOrder(request);
// 2. 扣减库存
inventoryService.decreaseStock(request.getItems());
// 3. 处理支付 - 独立事务
paymentService.processPayment(order.getPaymentInfo());
// 4. 发送通知 - 非事务
notificationService.sendOrderConfirmation(order);
}
// 库存扣减 - 加入主事务
@Transactional(propagation = Propagation.REQUIRED)
public void decreaseStock(List<OrderItem> items) {
for (OrderItem item : items) {
inventoryRepository.decreaseStock(item.getProductId(), item.getQuantity());
}
}
}
@Service
public class PaymentService {
// 支付处理 - 独立事务,失败不影响订单创建
@Transactional(
propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.SERIALIZABLE // 最高一致性要求
)
public void processPayment(PaymentInfo paymentInfo) {
// 支付逻辑
Payment payment = paymentRepository.save(new Payment(paymentInfo));
// 记录支付日志 - 再创建独立事务
auditService.logPayment(payment);
}
}
@Service
public class NotificationService {
// 通知发送 - 非事务执行
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void sendOrderConfirmation(Order order) {
// 发送邮件/短信通知
// 不需要数据库事务
emailService.sendConfirmation(order);
}
}
@Service
public class DataMigrationService {
// 批量迁移 - 使用嵌套事务支持部分回滚
@Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRED
)
public MigrationResult migrateBatch(List<DataRecord> records) {
MigrationResult result = new MigrationResult();
for (DataRecord record : records) {
try {
migrateRecord(record); // 嵌套事务
result.addSuccess(record);
} catch (Exception e) {
result.addFailure(record, e);
// 单条记录失败不影响整体批次
}
}
// 保存批次处理结果
migrationRepository.saveBatchResult(result);
return result;
}
// 单条记录迁移 - 嵌套事务
@Transactional(propagation = Propagation.NESTED)
private void migrateRecord(DataRecord record) {
// 数据转换和保存
ConvertedData data = dataConverter.convert(record);
targetRepository.save(data);
// 更新迁移状态
record.setMigrated(true);
sourceRepository.save(record);
}
}
业务场景 | 推荐隔离级别 | 原因 |
---|---|---|
金融交易 | SERIALIZABLE | 绝对不能有数据不一致 |
账户余额查询 | REPEATABLE_READ | 确保同一事务内读取一致 |
一般业务操作 | READ_COMMITTED | 平衡性能和一致性 |
统计报表 | READ_COMMITTED | 允许读取最新提交数据 |
高并发查询 | READ_UNCOMMITTED | 性能优先,可容忍脏读 |
业务场景 | 推荐传播属性 | 原因 |
---|---|---|
普通业务方法 | REQUIRED | 确保事务执行 |
审计日志 | REQUIRES_NEW | 独立保存,不受业务回滚影响 |
批量处理 | NESTED | 支持部分回滚 |
查询方法 | SUPPORTS | 可选事务,性能优先 |
计算密集操作 | NOT_SUPPORTED | 避免长时间占用连接 |
核心业务组件 | MANDATORY | 强制事务约束 |
外部API调用 | NEVER | 避免事务超时 |
// 性能测试对比
@Component
public class IsolationPerformanceTest {
// 高并发场景下的性能对比
@Transactional(isolation = Isolation.SERIALIZABLE)
public void serializable() {
// 最安全但性能最差
// 大量锁竞争,吞吐量低
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public void readCommitted() {
// 平衡选择
// 适合大多数业务场景
}
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void readUncommitted() {
// 性能最高但风险大
// 只在特殊场景使用
}
}
从源码可以看出,REQUIRES_NEW
和NOT_SUPPORTED
需要挂起和恢复事务:
// AbstractPlatformTransactionManager.suspend()方法
protected final SuspendedResourcesHolder suspend(Object transaction) throws TransactionException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 挂起同步化信息
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
// 保存事务状态
String name = TransactionSynchronizationManager.getCurrentTransactionName();
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
// 创建挂起资源持有者
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
// ...
}
性能建议:
REQUIRES_NEW
,因为事务挂起/恢复有额外开销// 错误:隔离级别不会生效
@Transactional(
propagation = Propagation.SUPPORTS, // 可能不创建新事务
isolation = Isolation.SERIALIZABLE // 隔离级别无效
)
public void problematicMethod() {
// 隔离级别只在新事务时生效
}
// 正确:确保创建新事务
@Transactional(
propagation = Propagation.REQUIRED, // 确保有事务
isolation = Isolation.SERIALIZABLE
)
public void correctMethod() {
// 隔离级别会生效
}
// 错误:内部方法事务不会生效(同一对象调用)
@Service
public class OrderService {
@Transactional
public void createOrder() {
saveOrder();
this.processPayment(); // 不会创建新事务!
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void processPayment() {
// 这个注解不会生效
}
}
// 正确:通过Spring代理调用
@Service
public class OrderService {
@Autowired
private PaymentService paymentService; // 注入其他Service
@Transactional
public void createOrder() {
saveOrder();
paymentService.processPayment(); // 会创建新事务
}
}
隔离级别和传播属性是Spring事务管理的两大核心机制:
隔离级别专注于解决数据一致性问题:
传播属性专注于解决事务边界管理问题:
理解这两个维度的问题与解决方案,能够帮助我们在复杂的企业级应用中设计出既高效又可靠的事务管理策略。在实际应用中,应该根据具体的业务需求、性能要求和数据一致性要求来选择合适的配置组合。