定义:编程式事务是指通过显式的编程代码来管理事务的开始、提交和回滚。开发者需要手动控制事务的每个步骤。
优点:
缺点:
示例(以Spring
的编程式事务为例):
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class TransactionService {
private final PlatformTransactionManager transactionManager;
public TransactionService(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void executeInTransaction() {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务逻辑
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
这段代码展示了如何使用Spring
进行编程式事务管理。executeInTransaction
方法中,首先创建了一个事务定义和事务状态。然后,在try
代码块中执行业务逻辑,并在成功时提交事务。如果发生异常,则回滚事务。通过这种方式,可以精细控制事务的开始、提交和回滚,适用于需要复杂事务控制的场景。
定义:声明式事务是通过配置或注解的方式来管理事务。开发者无需手动编写事务管理代码,事务的控制交由框架处理。
优点:
缺点:
示例(以Spring
的声明式事务为例):
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class TransactionService {
@Transactional
public void executeInTransaction() {
// 业务逻辑
}
}
在Spring
中,通常推荐使用声明式事务,因为它更加简洁并且可以充分利用Spring
框架的事务管理功能。在需要复杂事务控制时,可以考虑使用编程式事务。
对于需要部分事务回滚的复杂场景,Spring
中的声明式事务确实可以通过传播行为来实现一定的灵活控制。以下是一个详细的示例,展示如何使用常见的传播行为来实现部分事务回滚。
复杂混合事务场景示例:
假设有一个订单处理系统,包含以下步骤:
我们希望在处理过程中:
代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Autowired
private InventoryService inventoryService;
@Autowired
private EmailService emailService;
@Transactional(propagation = Propagation.REQUIRED)
public void processOrder(Order order) {
// Step 1: 创建订单(主事务)
createOrder(order);
try {
// Step 2: 扣减库存(嵌套事务)
inventoryService.deductInventory(order);
} catch (Exception e) {
// 仅回滚扣减库存这部分,不影响订单创建
System.err.println("扣减库存失败: " + e.getMessage());
}
// Step 3: 发送确认邮件(新事务)
emailService.sendOrderConfirmation(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createOrder(Order order) {
// 创建订单的逻辑
// 如果失败,抛出异常,整个事务回滚
if (order == null) {
throw new RuntimeException("订单创建失败");
}
}
}
库存服务InventoryService
@Service
public class InventoryService {
@Transactional(propagation = Propagation.NESTED)
public void deductInventory(Order order) {
// 扣减库存的逻辑
// 如果失败,抛出异常,仅回滚此嵌套事务
if (order.getItems().isEmpty()) {
throw new RuntimeException("库存扣减失败");
}
}
}
邮件服务EmailService
@Service
public class EmailService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void sendOrderConfirmation(Order order) {
// 发送确认邮件的逻辑
// 失败也不会影响主事务
if (order.getEmail() == null) {
throw new RuntimeException("邮件发送失败");
}
}
}
解释
REQUIRED
传播行为,作为主事务。如果失败,会抛出异常,导致整个事务回滚。NESTED
传播行为,在主事务内创建一个嵌套事务。如果扣减库存失败,只会回滚这个嵌套事务,不会影响到主事务。REQUIRES_NEW
传播行为,总是创建一个新的事务。即使发送邮件失败,也不会影响前面的事务。通过结合使用事务不同的传播行为,可以在声明式事务中实现复杂的事务管理需求,如部分事务回滚。
整个事务处理过程时序图如下:
时序图解释
OrderService
的 processOrder
方法开始主事务。OrderService
中创建订单,使用 REQUIRED
传播行为。InventoryService
扣减库存,使用 NESTED
传播行为。如果库存扣减失败,只回滚嵌套事务,不影响主事务。EmailService
发送确认邮件,使用 REQUIRES_NEW
传播行为。即使邮件发送失败,也不影响主事务。有人可能疑惑了,这里NESTED
和REQUIRES_NEW
的传播行为看起来很像,这里详细对比一下。
1. 事务关系:
REQUIRES_NEW:
NESTED:
REQUIRED
相同,创建一个新事务。2. 回滚和提交行为
REQUIRES_NEW:
NESTED:
3. 使用场景
REQUIRES_NEW:
NESTED:
欢迎一键三连~
有问题请留言,大家一起探讨学习
----------------------Talk is cheap, show me the code-----------------------
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。