今天将分享 Spring Boot 事务管理的新主题。
让我们开始吧,我阅读了关于交易管理的示例和博客,所有这些都给出了银行领域的示例。这可能是与主题相关的很好且简单的示例。
假设 A 使用他们的银行账户将钱汇给 B。所以这种情况,
A 向 B 发送 100 美元,让我们看看它是如何完成的。
- 开始交易:开始新交易。
- UPDATE accounts SET balance = balance — 100.00 WHERE id = 1: 从 A 的余额中扣除 100 美元。
- UPDATE accounts SET balance = balance + 100.00 WHERE id = 2: 向 B 的余额添加 100 美元。
- COMMIT:提交事务,使所有更改永久化。
假设数据库或进程内的任何资源不可用。我们必须确保数据库的 ACID,我希望您已经听说过这些概念,
- Atomicity: 确保事务中的所有操作均成功完成。如果任何操作失败,则整个事务失败,并且数据库保持不变。
- Consistency: 确保事务将数据库从一种有效状态转变为另一种有效状态。
- Isolation: 确保事务的中间状态对其他事务不可见。
- Durability: 确保事务一旦提交,即使在系统出现故障的情况下,事务也将保持不变。
我们必须确保在这个关键点上,业务逻辑需要事务管理。它必须决定是回滚整个事务、撤消更改,还是提交事务、确认迄今为止所做的更改。
此时我们需要事务管理来确保一致性和完整性。我们不需要手动配置事务管理,所有困难的事情都由 spring 完成,我们需要在代码中正确且合适的位置应用注释,就这样。
让我们通过上面的一个例子来清楚地了解它。
@Transactional
Spring 管理事务提供了注解。该注释可以在类和方法上定义。在 Spring Boot 中,事务管理不需要配置。但在 Spring 中,它需要配置。
- Propagation.REQUIRED: 如果事务已经存在,则该方法将在该事务内执行。如果不存在交易,则会创建一个新交易。
- Propagation.REQUIRES_NEW: 始终启动一个新事务,并暂停当前事务(如果存在)。
- Propagation.MANDATORY: 需要现有交易。如果不存在事务,则会抛出异常。
- Propagation.NESTED: 如果事务存在,则在嵌套事务中执行,否则行为类似于 Propagation.REQUIRED。
- Propagation.NEVER: 以非事务方式执行,如果存在事务则抛出异常。
- Propagation.NOT_SUPPORTED: 以非事务方式执行,暂停当前事务(如果存在)。
- Propagation.SUPPORTS: 如果存在事务,则在事务内执行,否则以非事务方式执行。
我将在本文中解释每一个,所以不必害怕。🙂。
Propagation.REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
我经常使用这个东西,这不是唯一的方法。考虑这个例子,
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 MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void performOperations() {
try {
// Perform some database operations
myRepository.save(new Entity());
myRepository.update(existingEntity);
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Transaction failed", e);
}
}
}
@Transactional 注解应用于 performOperations 方法。这告诉 Spring 管理该方法的事务。
propagation = Propagation.REQUIRED
属性指定如果事务已经存在,则该方法将在该事务中执行。如果不存在交易,则会创建一个新交易。
如果在 performOperations 方法中发生任何异常,事务将被回滚,以确保数据库保持一致的状态。
如果该方法成功完成,则将提交事务。
对于这个必需的传播,我们不需要默认提及,它是必需的。
在 Spring 中,@Transactional 注解的默认传播行为是 Propagation.REQUIRED
。这意味着如果您没有显式指定传播行为,Spring 将默认使用 Propagation.REQUIRED
。
这是上一个示例的简化版本,没有明确指定传播行为:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@Transactional
public void performOperations() {
try {
// Perform some database operations
myRepository.save(new Entity());
myRepository.update(existingEntity);
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Transaction failed", e);
}
}
}
所以我忘了提到 Spring 中的 AOP(面向方面编程)。事务管理是通过面向方面编程(AOP)来促进的。 AOP 有效地将横切关注点与核心业务逻辑分开。在典型的n层架构中,包括表示层(API层)、业务层(服务层)和数据访问层(存储层),横切关注点通常在业务层内定义。这些问题涵盖安全性、验证、事务管理、日志记录、性能优化和其他相关流程等方面。这确实增强了代码的清晰度。我仍在学习 Spring Framework 和 Spring Boot。
Spring 中的面向方面编程 (AOP)
AOP 是一种编程范式,旨在通过允许分离横切关注点来提高模块化性。在 Spring 的上下文中,AOP 用于跨多个方法或类应用事务管理、日志记录、安全性和验证等行为,而无需修改底层代码。
使用 AOP 进行事务管理
Spring 的事务管理是如何使用 AOP 来分离横切关注点的经典示例。当您使用 @Transactional
注释方法或类时,Spring 使用 AOP 围绕注释方法编织事务管理。这意味着事务管理逻辑是自动应用的,而不会用事务相关的代码扰乱您的业务逻辑。
典型的 N 层架构
在典型的 n 层架构中,各层通常组织如下:
- 表示层(API 层):处理用户请求和响应。该层负责通过 API 公开应用程序的功能。
- 业务层(Service 层):包含应用程序的核心业务逻辑。该层协调数据流和操作。
- 数据访问层(Repository 层):与数据库或其他数据源交互。该层负责 CRUD 操作。
跨领域的关注点
横切关注点是影响应用程序多个部分的方面,但不是应用程序的核心功能。这些担忧包括:
- 事务管理:确保数据库操作以原子方式执行。
- 安全性:实施访问控制和身份验证。
- 验证:验证输入数据以确保其满足特定标准。
- 日志记录:记录重要事件和错误以进行调试和监控。
- 性能优化:优化应用程序的性能。
使用 AOP 进行事务管理的好处
- 关注点分离:事务管理逻辑与核心业务逻辑分离,使代码更干净、更易于维护。
- 可重用性:事务管理可以一致地应用于多个方法和类,而无需重复代码。
- 可维护性:可以在一处对事务管理逻辑进行更改,从而降低错误和不一致的风险。
对于您的信息-通过使用 AOP 进行事务管理,Spring 可以让开发人员专注于编写业务逻辑,而不必担心事务管理的复杂性。这种方法增强了代码的清晰度、可维护性和模块化性,使开发和维护复杂的应用程序变得更加容易。
回到主题,
第二种传播类型是 Required_new
.
REQUIRES_NEW
REQUIRES_NEW 此传播类型对于大多数情况非常有用。如果会话在 REQUIRES_NEW 之前启动,它将挂起前一个会话并创建一个新会话。之前的交易不会影响这一点。这意味着如果前一个事务发生错误,REQUIRES_NEW 将不会受到该错误的影响。
@Transactional(propagation = Propagation.REQUIRED)
public void create(Product product, List<Image> images) {
saveImages(images);
productRepository.save(product);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveImages(List<Image> images) {
// save images
}
使用案例
- 独立操作:当您需要执行不应受当前事务结果影响的操作时。
- 错误处理:当您想要确保某些操作在外部事务失败时不会回滚时。
- 审核日志记录:当您需要独立于主事务记录某些操作时。
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 MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void performOperations() {
try {
// Perform some database operations within the current transaction
myRepository.save(new Entity());
// Call a method that requires a new transaction
performIndependentOperation();
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Transaction failed", e);
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void performIndependentOperation() {
try {
// Perform some database operations within a new transaction
myRepository.update(existingEntity);
// If everything is successful, the new transaction will be committed
} catch (Exception e) {
// If any exception occurs, the new transaction will be rolled back
throw new RuntimeException("Independent operation failed", e);
}
}
}
performOperations 方法:
该方法使用 @Transactional(propagation = Propagation.REQUIRED) 注解,这意味着如果存在则加入当前事务,如果不存在则启动一个新事务。
它执行一些数据库操作,然后调用 performIndependentOperation。
performIndependentOperation 方法
该方法使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 注解,这意味着它将始终启动一个新事务,如果存在则暂停当前事务。
它在这个新事务中执行一些数据库操作。
行为,当调用 PerformOperations 时,它会启动一个新事务(或加入一个现有事务)。
当从 performOperations 中调用 performIndependentOperation 时,将启动一个新事务,并挂起当前事务。
如果 performIndependentOperation 成功完成,则提交新事务。
如果 performIndependentOperation 抛出异常,则回滚新事务,但挂起的事务不受影响。
PerformIndependentOperation() 完成后,挂起的事务将恢复。
好处:
- 隔离:确保 performIndependentOperation 中的操作与主事务隔离。
- 错误处理:允许更精细的错误处理,因为独立操作的失败不一定会影响主事务。
- 审核日志记录:对于应独立于主事务进行记录的日志记录或审核操作很有用。
另一种是支持。
Propagation.SUPPORT
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 MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void performOperations() {
try {
// Perform some database operations within the current transaction
myRepository.save(new Entity());
// Call a method that supports an existing transaction
performOptionalTransactionalOperation();
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Transaction failed", e);
}
}
@Transactional(propagation = Propagation.SUPPORTS)
public void performOptionalTransactionalOperation() {
try {
// Perform some database operations
myRepository.update(existingEntity);
// If a transaction is active, this operation will participate in it
// If no transaction is active, this operation will run non-transactionally
} catch (Exception e) {
// Handle exceptions as needed
throw new RuntimeException("Optional operation failed", e);
}
}
}
在此代码中,当调用 performOperations 时,它会启动一个新事务(或加入一个现有事务)。
当从 performOperations 中调用 performOptionalTransactionalOperation 时,它会参与现有事务。
如果在任何事务上下文之外调用 performOptionalTransactionalOperation,它将以非事务方式运行。
Propagation.NOT_SUPPORTED.
Spring 事务管理中的传播行为用于指示方法不应在事务内运行。如果调用该方法时事务处于活动状态,则该事务将挂起,并且该方法以非事务方式运行。此行为对于不需要事务保证的只读操作特别有用,可能会提高性能。
Propagation.NOT_SUPPORTED
- 挂起现有事务:如果调用该方法时事务处于活动状态,则该事务将挂起。
- 非事务性执行:该方法以非事务性方式运行。
- 恢复事务:该方法完成后,恢复暂停的事务。
使用案例
- 只读操作:当您有只从数据库读取数据而不修改数据的方法时。
- 性能优化:通过避免只读操作的事务管理开销来提高性能。
- 外部服务:当调用外部服务或执行不需要事务保证的操作时。
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 MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void performOperations() {
try {
// Perform some database operations within the current transaction
myRepository.save(new Entity());
// Call a method that does not support transactions
performNonTransactionalOperation();
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Transaction failed", e);
}
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void performNonTransactionalOperation() {
try {
// Perform some database operations non-transactionally
myRepository.readData();
// This operation runs without a transaction, even if a transaction was active
} catch (Exception e) {
// Handle exceptions as needed
throw new RuntimeException("Non-transactional operation failed", e);
}
}
}
performOperations 方法:
该方法使用 @Transactional(propagation = Propagation.REQUIRED) 注解,这意味着如果存在则加入当前事务,如果不存在则启动一个新事务。
它执行一些数据库操作,然后调用 performNonTransactionalOperation。
performNonTransactionalOperation 方法:
此方法用 @Transactional(propagation = Propagation.NOT_SUPPORTED) 注释,这意味着它将挂起任何活动事务并以非事务方式运行。
它以非事务方式执行一些数据库操作。
Propagation.NEVER
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 MyService {
@Autowired
private MyRepository myRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void performOperations() {
try {
// Perform some database operations within the current transaction
myRepository.save(new Entity());
// Call a method that should never run within a transaction
performNonTransactionalOperation();
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Transaction failed", e);
}
}
@Transactional(propagation = Propagation.NEVER)
public void performNonTransactionalOperation() {
try {
// Perform some operations that must not be part of a transaction
myRepository.readData();
// This operation runs without a transaction, and an exception will be thrown if a transaction is active
} catch (Exception e) {
// Handle exceptions as needed
throw new RuntimeException("Non-transactional operation failed", e);
}
}
}
行为:
当调用 performOperations 时,它会启动一个新事务(或加入一个现有事务)。
当从 performOperations 中调用 performNonTransactionalOperation 时,将引发异常,因为事务处于活动状态。
必须在任何事务上下文之外调用 performNonTransactionalOperation 以避免引发异常。
- 严格执行:确保某些操作永远不会成为任何事务的一部分,从而明确区分事务性和非事务性逻辑。
- 错误预防:防止在事务中意外包含非事务逻辑,这有助于避免细微的错误并确保正确的行为。
Propagation.mandatory.
Spring 事务管理中的传播行为用于指示方法必须始终在事务内运行。如果调用该方法时没有活动的事务,则会抛出异常。此行为可确保该方法始终在事务上下文中执行,这对于维护数据一致性和完整性至关重要。
Propagation.MANDATORY
- 需要事务:该方法必须在事务内运行。
- 无事务异常:如果调用该方法时没有活动事务,则会抛出异常。
使用案例
- 关键操作:当您的操作必须始终是事务的一部分以确保数据一致性和完整性时,例如金融交易、支付处理或其他关键业务逻辑。
- 确保事务上下文:当您需要确保方法始终在事务上下文中执行时,无论调用上下文如何。
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 PaymentService {
@Autowired
private PaymentRepository paymentRepository;
@Transactional(propagation = Propagation.REQUIRED)
public void processPayment(Payment payment) {
try {
// Perform some database operations within the current transaction
paymentRepository.save(payment);
// Call a method that requires a transaction
validatePayment(payment);
// If everything is successful, the transaction will be committed
} catch (Exception e) {
// If any exception occurs, the transaction will be rolled back
throw new RuntimeException("Payment processing failed", e);
}
}
@Transactional(propagation = Propagation.MANDATORY)
public void validatePayment(Payment payment) {
try {
// Perform some validation operations that must be part of a transaction
paymentRepository.updateStatus(payment, "VALIDATED");
// This operation runs within a transaction, and an exception will be thrown if no transaction is active
} catch (Exception e) {
// Handle exceptions as needed
throw new RuntimeException("Payment validation failed", e);
}
}
}
processPayment 方法:
该方法使用 @Transactional(propagation = Propagation.REQUIRED) 注解,这意味着如果存在则加入当前事务,如果不存在则启动一个新事务。
它执行一些数据库操作,然后调用 validatePayment。
validatePayment 方法:
该方法使用 @Transactional(propagation = Propagation.MANDATORY) 注解,这意味着如果调用该方法时没有事务处于活动状态,则会抛出异常。
它执行一些必须属于事务一部分的验证操作。
当调用 processPayment 时,它会启动一项新交易(或加入现有交易)。
当从 processPayment 中调用 validatePayment 时,它会在现有事务中运行。
如果在任何事务上下文之外调用 validatePayment,则会抛出异常,因为没有活动的事务。
好处:
- 数据一致性:确保关键操作始终在事务内执行,保持数据的一致性和完整性。
- 错误预防:防止在事务上下文之外意外执行关键操作,这有助于避免细微的错误并确保正确的行为
原文地址