spring事务传播机制及事务失效的场景
时间: 2023-08-17 14:05:41 AIGC 浏览: 156
Spring事务传播机制是指在多个事务方法调用的场景下,如何管理这些事务的提交和回滚。Spring提供了多种事务传播行为,包括:
1. REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是最常用的传播行为。
2. REQUIRES_NEW:每次都创建一个新的事务,如果当前存在事务,则将其挂起。
3. SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
4. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则将其挂起。
5. MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
6. NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
7. NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。嵌套事务是外部事务的一部分,它有自己的保存点和回滚范围。
事务失效的场景包括:
1. 异常未被捕获并处理,导致事务没有正常回滚。
2. 在没有开启事务的情况下调用带有@Transactional注解的方法,导致方法执行时没有开启事务。
3. 在同一个类中的方法互相调用,而没有通过代理对象进行调用,导致事务失效。
4. 在事务方法中使用了try-catch块并捕获了异常,没有主动抛出异常或调用setRollbackOnly方法,导致事务无法回滚。
需要注意的是,事务的失效可能与具体的配置和使用方式有关,详细的分析和排查需要根据具体的代码和配置进行。
相关问题
spring事务传播机制?失效场景?
Spring事务传播机制定义了一个方法在调用其他方法时如何传播其事务上下文。以下是Spring事务传播机制的7个选项:
1. REQUIRED:如果当前已经存在事务,则加入该事务;否则,创建新事务。
2. SUPPORTS:如果当前存在事务,则加入该事务;否则,以非事务方式继续执行。
3. MANDATORY:当前必须存在事务;否则,抛出异常。
4. REQUIRES_NEW:创建新的事务,并挂起当前事务(如果存在)。
5. NOT_SUPPORTED:以非事务方式执行,并挂起当前事务(如果存在)。
6. NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7. NESTED:如果当前存在事务,则在嵌套事务中执行;否则,创建新事务。
失效场景包括:
1. 未使用@Transactional注解或者编程式事务管理
2. 异常被catch而没有往上抛出,导致事务没有回滚
3. 同一个类内部的方法调用,没有走代理对象,导致事务失效
4. 不同类的方法调用,如果调用的方法没有使用@Transactional注解或者编程式事务管理,会导致事务失效
spring事务失效场景及
### Spring 框架事务管理失效的常见场景及其解决方案
#### 场景一:未启用事务管理
当应用程序配置中缺少 `@EnableTransactionManagement` 注解或 XML 配置中的 `<tx:annotation-driven/>` 时,即使方法上标注了 `@Transactional`,也不会有任何效果。
解决办法是在启动类或配置文件中加入必要的声明来开启基于注解的事务支持[^2]。
```java
@Configuration
@EnableTransactionManagement
public class AppConfig {
// Configuration code here...
}
```
#### 场景二:异常被捕获并吞掉
如果在一个带有 `@Transactional` 的方法内部捕获到了异常却没有抛出,那么这个异常就不会触发回滚操作。这通常发生在开发者为了防止程序崩溃而简单地忽略了错误的情况之下。
应当让受控业务逻辑能够感知到发生的异常以便决定是否继续执行流程;对于不可恢复性的严重问题则应允许其传播给调用者从而实现自动回滚机制[^3]。
#### 场景三:使用异步方式调用服务层接口
由于默认情况下每个线程都有独立的作用域,在多线程环境下可能会遇到无法识别当前存在的事务上下文的问题。因此直接通过代理对象同步访问其他组件的方法可以正常工作,但是利用诸如 `CompletableFuture.runAsync()` 或者 `@Async` 这样的特性就会破坏原有链路内的事务状态传递关系。
建议采用编程式的 TransactionTemplate 来手动控制子任务所属父级事物边界范围,或者调整为同一线程内顺序化处理模式以维持一致的行为表现形式。
#### 场景四:违反只读属性设置原则
某些持久化引擎(比如 Hibernate)会因为开启了 flush() 自动刷新策略而在查询期间意外修改实体字段进而导致脏写入现象发生。此时即便指定了 readOnly=true 参数也无法阻止此类变更动作的发生。
最佳实践是要确保所有参与同一笔交易过程里的 DAO 层交互都遵循相同的存取权限级别定义,并且尽可能减少不必要的更新语句频率以免影响性能指标和并发安全性[^1]。
#### 场景五:跨多个不同数据源的操作
一旦涉及到两个以上相互关联却又隶属于各自独立连接池资源的对象实例之间的协作互动,就很容易引发分布式一致性难题。特别是当其中一个环节失败之后怎样安全地中止整个批次提交成为了一个棘手的技术挑战。
推荐做法是引入 XA 协议兼容型中间件产品如 Atomikos、Bitronix 等来进行全局协调调度,亦或是重构设计思路使之转换成幂等性质更强的服务单元组合而成的整体架构体系结构。
#### 场景六:嵌套式调用同一个 Bean 方法
假设有 A 和 B 是由相同容器实例化的单例 bean ,而且它们之间存在互相依赖关系即 A 调用了 B 中同样加有 @Transactional 标记函数 C 。然而根据 JDK 动态代理原理可知除非经过特殊定制否则普通反射手段难以穿透内部私有成员变量所指向的目标对象的真实身份信息,所以这里很可能造成新的外部包裹层而非继承已有正在进行之中的那个共享环境。
为了避免上述情况出现,应该考虑重新规划模块间的职责划分界限,尽量避免循环引用情形的同时也方便后期维护人员理解整体运作机理。
#### 场景七:Propagation 设置不合理
不同的 Propagation 枚举值决定了新发起请求如何融入现有活动之中去。如果不小心选择了不当选项的话,很可能会引起意想不到的结果,例如重复创建额外级别的隔离副本或者是忽视已经存在的约束条件限制等等。
务必仔细权衡各种可能性后再做出最终抉择,一般而言 REQUIRED 类型最为常用因为它能够在必要时候新建 session 同时又能很好地复用已有的 context 结构体。
#### 场景八:Rollback For 不匹配
只有那些显式指定要响应的具体 Exception 子类别才会促使系统强制终止当前正在运行的任务流并且撤销之前所做的任何更改记录。反之如果没有特别说明的话,默认只会对 unchecked runtime exception 生效而已。
所以在编写 catch block 分支判断逻辑的时候一定要谨慎行事,最好把所有可能遇见的风险因素全部罗列出来加以防范措施部署到位。
阅读全文
相关推荐















