事务传播机制定义了当一个事务性方法被调用时,这个方法应该如何处理事务。它决定了方法执行时是应该加入到现有的事务中、创建一个新的事务、还是以非事务方式执行等。具体来说,事务传播机制影响的是当前方法的事务上下文,而不是该方法内部调用的其他方法。
1. 传播机制
Spring事务的传播机制定义了事务如何在不同方法之间传播。Spring支持以下七种事务传播行为:
-
PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,就新建一个事务。这是默认值。
-
PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前没有事务,就以非事务方式执行。
-
PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前没有事务,就抛出异常。
-
PROPAGATION_REQUIRES_NEW:无论当前是否存在事务,都新建事务,并暂停当前事务。
-
PROPAGATION_NOT_SUPPORTED:总是非事务地执行操作,如果当前存在事务,就将其挂起。
-
PROPAGATION_NEVER:总是非事务地执行操作,如果当前存在事务,则抛出异常。
-
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则表现得像PROPAGATION_REQUIRE。
2. 案例
2.1 PROPAGATION_REQUIRED(默认)
@Service
public class AccountService {
@Transactional
public void transferFunds(Account from, Account to, BigDecimal amount) {
from.setBalance(from.getBalance().subtract(amount));
to.setBalance(to.getBalance().add(amount));
// 这两个操作会在同一个事务中提交或回滚
}
}
transferFunds
方法会确保两个操作(扣款和存款)都在同一个事务中执行。如果其中一个操作失败,整个事务会回滚,确保账户余额的一致性。
2.2 PROPAGATION_REQUIRES_NEW
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createOrder(Order order) {
// 这个方法总是会创建一个新的事务
// 即使外部有事务也会被挂起
orderRepository.save(order);
}
}
createOrder
方法总是会创建一个新的事务,即使它被一个已经存在的事务中的另一个方法调用。这意味着createOrder
方法的事务是独立的,不会受到外部事务的影响。
2.3 PROPAGATION_SUPPORTED
@Service
public class SupportedService {
@Transactional(propagation = Propagation.SUPPORTED)
public void canSupported() {
// 如果调用方法具有事务,则加入事务
// 没有事务,该方法以非事务方法执行
reportRepository.save(newReport());
}
}
2.4 PROPAGATION_NOT_SUPPORTED
@Service
public class ReportingService {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void generateReport() {
// 这个方法将不在事务中执行
// 即使外部有事务也会被忽略
reportRepository.save(newReport());
}
}
generateReport
方法总是会以非事务方式执行,即使它被一个事务性方法调用。这适用于那些不需要事务管理的操作,比如生成报告、发送邮件等。
2.5 PROPAGATION_MANDATORY
@Service
public class AuditService {
@Transactional(propagation = Propagation.MANDATORY)
public void logAudit(AuditEntry entry) {
// 这个方法只能在事务中被调用
// 如果外部没有事务,将会抛出异常
auditRepository.save(entry);
}
}
logAudit
方法只能在事务中被调用。如果尝试在没有事务的上下文中调用此方法,将会抛出异常。
2.6 PROPAGATION_NEVER
@Service
public class SensitiveService {
@Transactional(propagation = Propagation.NEVER)
public void handleSensitiveData() {
// 这个方法永远不会在事务中执行
// 如果外部有事务,将会抛出异常
sensitiveRepository.save(newSensitiveData());
}
}
handleSensitiveData
方法永远不会在事务中执行。如果尝试在事务的上下文中调用此方法,将会抛出异常。
2.7 PROPAGATION_NESTED
@Service
public class NestedTransactionalService {
@Transactional(propagation = Propagation.NESTED)
public void outerTransaction() {
// 外部事务
saveSomeData();
innerTransaction();
}
@Transactional(propagation = Propagation.NESTED)
public void innerTransaction() {
// 内部事务,可以独立于外部事务提交或回滚
saveMoreData();
}
}
outerTransaction
方法开启了一个外部事务,而innerTransaction
方法开启了一个嵌套事务。嵌套事务可以独立于外部事务进行提交或回滚,这在需要在同一个大事务中执行多个小事务时非常有用。
打重点:事务传播机制主要关注的是事务性方法本身在被调用时如何处理事务,而不是该方法内部如何调用其他方法!