@transactional回滚的流程
时间: 2023-09-01 18:12:25 浏览: 112
当使用 @Transactional 注解时,Spring 会为被注释的方法创建一个代理对象,在方法开始时开启一个事务,在方法结束时提交或回滚事务。如果方法抛出异常,则事务会自动回滚。
当事务回滚时,Spring 会执行以下步骤:
1. 关闭连接:Spring 会关闭所有使用的数据库连接,确保连接不再使用。
2. 回滚操作:Spring 会执行事务回滚操作,将所有已经执行的 SQL 操作全部回滚,确保数据的一致性。
3. 异常处理:Spring 会将异常信息记录到日志中,并且将异常向上抛出,让上层调用者处理。
需要注意的是,@Transactional 注解只对运行时异常进行回滚,对于检查时异常则不进行回滚。如果需要对检查时异常进行回滚,可以使用 rollbackFor 属性指定需要回滚的异常类型。
相关问题
@Transactional 和@asnyc在同一个方法为什么回滚不生效
### @Transactional 和 @Async 同时注解导致事务回滚失效的原因
当 `@Transactional` 和 `@Async` 注解同时应用在一个方法上时,可能会遇到事务管理不按预期工作的情况。具体来说,在异步方法中标记的事务可能不会按照期望的方式进行回滚。
#### 原因分析
1. **代理机制差异**
Spring 使用不同的代理策略来处理 `@Transactional` 和 `@Async` 的行为。对于 `@Transactional`,通常采用的是基于 JDK 动态代理或 CGLIB 字节码增强技术;而 `@Async` 则依赖于特定的任务执行器(TaskExecutor)。这两种代理模式之间存在冲突,使得两者不能很好地协同工作[^2]。
2. **线程上下文隔离**
当一个带有 `@Async` 的方法被执行时,它会在一个新的线程中运行。然而,默认情况下,Spring 的事务传播机制是在当前线程范围内有效的。因此,一旦进入新的线程环境,原有的事务上下文就会丢失,从而导致即使发生了异常也无法触发回滚操作[^3]。
3. **异常捕捉范围有限**
如果在异步方法内部发生的异常被捕获并吞掉了,则外部主线程无从知晓这些异常的发生情况,进而无法做出相应的反应如回滚等动作[^4]。
```java
@Service
public class AsyncService {
@Async
@Transactional(rollbackFor = Exception.class)
public void asyncMethodWithTransaction() {
// Some database operations here...
throw new RuntimeException("Simulated exception");
}
}
```
上述代码片段展示了尝试将两个注解组合使用的错误实践案例。尽管指定了 `rollbackFor=Exception.class` 参数试图让任何类型的未检查异常都能引起回滚,但由于以上提到的技术限制,实际效果往往不如人意。
---
### 解决方案建议
为了使 `@Transactional` 能够正常运作并与 `@Async` 协同合作,可以采取以下几种措施:
1. **分离职责**
将涉及数据库交互的操作放在同步的服务层方法里,并在此处添加 `@Transactional` 注解。而在另一个单独的方法上调用此服务层方法的同时加上 `@Async` 来实现真正的异步化处理流程。
2. **调整事务边界**
修改业务逻辑设计,确保所有必要的持久化变更都在同一个非异步的方法体内完成,这样就可以保证整个过程处于同一事务控制之下。
3. **利用编程式事务管理**
对于某些复杂场景下难以通过声明式的手段解决问题的情形,考虑改用编程的方式来显式开启/提交/回滚事务,以便更灵活地应对多变的需求条件。
```java
@Service
public class TransactionalService {
private final PlatformTransactionManager transactionManager;
@Autowired
public TransactionalService(PlatformTransactionManager transactionManager){
this.transactionManager = transactionManager;
}
@Async
public Future<Boolean> performOperationInNewThread(){
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(definition);
try{
// Execute some business logic that requires a transaction
transactionManager.commit(status);
return CompletableFuture.completedFuture(true);
}catch(Exception e){
transactionManager.rollback(status);
throw e;
}
}
}
```
这段示例说明了如何借助编程方式创建和管理事务状态,以适应更为复杂的并发处理需求。
@transactional原理
@Transactional是Spring框架提供的一个事务管理注解,作用是声明一个类或者方法需要使用事务控制。在调用带有@Transactional注解的方法时,Spring框架会在该方法开始执行时创建一个数据库事务,并在方法执行期间对所有数据库操作进行事务管理。一旦方法执行完毕,无论成功还是失败,Spring框架会根据事务的提交或者回滚状态对事务进行相应的处理。
@Transactional注解的本质是通过AOP(面向切面编程)技术实现事务管理。在Spring框架中,通过将@Transactional注解与事务切面结合使用,将其织入到代码的适当位置,完成事务管理的整个流程。在具体实现时,Spring框架通过与DataSourceTransactionManager和TransactionInterceptor等类的协作,实现了以下功能:
1. 开启事务:事务开始执行时,DataSourceTransactionManager会根据数据库连接创建一个JDBC事务对象,并将其与当前线程绑定,保证同一事务范围内的所有操作都使用同一连接对象。
2. 提交或回滚事务:当当前@Transactional注解标注的方法执行完毕后,TransactionInterceptor会根据方法的返回值和异常情况判断事务是否需要进行提交或者回滚操作,并在操作执行完成后释放与当前线程绑定的JDBC连接,以便其他线程使用。
3. 事务嵌套:当多个@Transactional注解标注的方法嵌套执行时,TransactionInterceptor会根据嵌套层级和事务传播属性设置来判断如何进行事务管理。如果被调用方法不存在@Transactional注解,则会采用调用方的事务进行管理。
总之,@Transactional注解为开发者提供了一个方便、快捷、可靠的事务管理方式,大大简化了事务管理的代码实现和维护成本。同时,其基于AOP的设计也体现了Spring框架的核心理念——面向切面编程,强调关注点分离,更好地实现了应用程序的可维护性和可扩展性。
阅读全文
相关推荐














