Spring框架提供了声明式事务管理,允许开发者通过配置来控制事务的行为。事务传播行为(Transaction Propagation Behavior)定义了在事务上下文中执行的方法如何与现有的事务关联。Spring定义了以下七种事务传播行为:
源码
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.transaction.annotation;
import org.springframework.transaction.TransactionDefinition;
/**
* Enumeration that represents transaction propagation behaviors for use
* with the {@link Transactional} annotation, corresponding to the
* {@link TransactionDefinition} interface.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @since 1.2
*/
public enum Propagation {
/**
* Support a current transaction, create a new one if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>This is the default setting of a transaction annotation.
*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
/**
* Support a current transaction, execute non-transactionally if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: For transaction managers with transaction synchronization,
* {@code SUPPORTS} is slightly different from no transaction at all,
* as it defines a transaction scope that synchronization will apply for.
* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
* will be shared for the entire specified scope. Note that this depends on
* the actual synchronization configuration of the transaction manager.
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
/**
* Support a current transaction, throw an exception if none exists.
* Analogous to EJB transaction attribute of the same name.
*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
/**
* Create a new transaction, and suspend the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
/**
* Execute non-transactionally, suspend the current transaction if one exists.
* Analogous to EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**
* Execute non-transactionally, throw an exception if a transaction exists.
* Analogous to EJB transaction attribute of the same name.
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@code REQUIRED} otherwise. There is no analogous feature in EJB.
* <p>Note: Actual creation of a nested transaction will only work on specific
* transaction managers. Out of the box, this only applies to the JDBC
* DataSourceTransactionManager. Some JTA providers might support nested
* transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
详细说明
REQUIRED
如果当前存在事务,就加入该事务;如果当前没有事务,就新建一个事务。这是默认的事务传播行为。
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void placeOrder(Order order) {
// 保存订单
this.saveOrder(order);
// 发送通知
this.sendNotification(order);
}
public void saveOrder(Order order) {
// 模拟数据库操作
}
public void sendNotification(Order order) {
// 模拟发送通知
}
}
在placeOrder
方法中,由于使用了REQUIRED
传播行为,它会加入当前的事务(如果存在)或者新建一个事务。saveOrder
和sendNotification
方法没有声明事务,因此它们会加入placeOrder
方法的事务中。
SUPPORTS
如果当前存在事务,就加入该事务;如果当前没有事务,就以非事务方式执行。
@Service
public class MarketingService {
@Resource
private EmailService emailService;
@Transactional(propagation = Propagation.SUPPORTS)
public void sendMarketingEmails() {
// 这个方法会在当前事务中执行,如果当前没有事务,则不会创建新事务。
emailService.sendEmailsToSubscribers();
}
}
@Service
public class SubscriptionService {
@Resource
private MarketingService marketingService;
// 如果当前存在事务,subscribeUser方法将在这个事务中执行。如果当前没有事务,subscribeUser方法将创建一个新的事务。
@Transactional(propagation = Propagation.REQUIRED)
public void subscribeUser(User user) {
// 这个方法会在新的或当前事务中执行。
subscriptionRepository.save(user);
// 由于sendMarketingEmails方法的传播行为是SUPPORTS,如果subscribeUser方法在一个事务中执行,sendMarketingEmails方法也会在这个事务中执行;如果subscribeUser方法没有在一个事务中执行,sendMarketingEmails将以非事务方式执行。
marketingService.sendMarketingEmails();
}
}
MANDATORY
如果当前存在事务,就加入该事务;如果当前没有事务,就抛出异常。
@Service
public class PaymentService {
@Transactional(propagation = Propagation.MANDATORY)
public void processPayment(Payment payment) {
// 这个方法必须在事务中执行,如果当前没有事务,将抛出异常。
paymentRepository.save(payment);
}
}
@Service
public class OrderService {
@Resource
private PaymentService paymentService;
@Transactional(propagation = Propagation.REQUIRED)
public void placeOrder(Order order) {
// 这个方法会在新的或当前事务中执行。
orderRepository.save(order);
// 调用PaymentService,它必须在事务中执行。
paymentService.processPayment(order.getPayment());
}
}
在<font style="color:rgb(6, 6, 7);">PaymentService</font>
中,<font style="color:rgb(6, 6, 7);">processPayment</font>
方法使用了<font style="color:rgb(6, 6, 7);">MANDATORY</font>
传播行为,这意味着它必须在一个事务中执行。如果<font style="color:rgb(6, 6, 7);">placeOrder</font>
方法在一个事务中调用<font style="color:rgb(6, 6, 7);">processPayment</font>
,那么支付处理将在这个事务中执行。如果没有事务,将抛出异常。
REQUIRES_NEW
总是新建一个事务,如果当前存在事务,就将当前事务挂起。
@Service
public class ProductService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductDetails(Product product) {
// 更新产品详情
this.productRepository.save(product);
// 发送通知
this.sendNotification(product);
}
public void sendNotification(Product product) {
// 模拟发送通知
}
}
在updateProductDetails
方法中,使用了REQUIRES_NEW
传播行为,这意味着每次调用这个方法时,都会创建一个新的事务,即使当前存在一个事务也会被挂起。
NOT_SUPPORTED
总是以非事务方式执行,如果当前存在事务,就将当前事务挂起。
@Service
public class ReportingService {
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void generateReport() {
// 生成报告,不需要事务
this.reportRepository.save(report);
}
}
在generateReport
方法中,使用了NOT_SUPPORTED
传播行为,这意味着即使当前存在事务,也会被挂起,这个方法将以非事务方式执行。
NEVER
总是以非事务方式执行,如果当前存在事务,就抛出异常。
@Service
public class ReportingService {
@Transactional(propagation = Propagation.NEVER)
public void generateReport() {
// 这个方法总是以非事务方式执行,如果当前存在事务,将抛出异常。
reportRepository.save(new Report());
}
}
@Service
public class OrderService {
@Resource
private ReportingService reportingService;
@Transactional(propagation = Propagation.REQUIRED)
public void processOrder(Order order) {
// 这个方法会在新的或当前事务中执行。
orderRepository.save(order);
// 调用ReportingService,它将以非事务方式执行。
reportingService.generateReport();
}
}
在<font style="color:rgb(6, 6, 7);">ReportingService</font>
中,<font style="color:rgb(6, 6, 7);">generateReport</font>
方法使用了<font style="color:rgb(6, 6, 7);">NEVER</font>
传播行为,这意味着它总是以非事务方式执行。如果<font style="color:rgb(6, 6, 7);">processOrder</font>
方法在一个事务中调用<font style="color:rgb(6, 6, 7);">generateReport</font>
,那么生成报告的操作将以非事务方式执行,如果当前存在事务,将抛出异常。
NESTED
如果当前存在事务,就在嵌套事务内执行。如果当前没有事务,就和REQUIRED一样新建一个事务。
@Service
public class UserService {
@Transactional(propagation = Propagation.REQUIRED)
public void registerUser(User user) {
// 注册用户
this.userRepository.save(user);
// 触发额外的操作
this.triggerAdditionalOperations(user);
}
@Transactional(propagation = Propagation.NESTED)
public void triggerAdditionalOperations(User user) {
// 执行一些需要嵌套事务的操作
this.additionalRepository.save(user);
}
}
在registerUser
方法中,使用了REQUIRED
传播行为,而在triggerAdditionalOperations
方法中使用了NESTED
传播行为。这意味着triggerAdditionalOperations
方法会在registerUser
方法的事务内执行,但它拥有自己的事务上下文,可以独立地进行回滚。