springboot事务的传播行为和隔离级别

springboot事务的传播行为和隔离级别

1. 在springboot中事务的传播行为和隔离级别都是在TransactionDefinition这个接口中定义的

  • 传播行为定义了7种,分别用0-6来表示
int PROPAGATION_REQUIRED = 0;//如果当前上下文中的已经存在一个事务,就使用当前的事务;如果当前没有事务就创建一个新的事务
int PROPAGATION_SUPPORTS = 1;//如果当前上下文中的已经存在一个事务,就使用当前的事务;如果当前没有事务也不会开启一个新事务,以非事务的方式执行
int PROPAGATION_MANDATORY = 2;//如果当前上下文中的已经存在一个事务,就使用当前的事务;如果当前没有事务就抛出异常
int PROPAGATION_REQUIRES_NEW = 3;//如果当前上下文中的已经存在一个事务,就暂停该事务;创建一个新的事务开始执行。完成后恢复之前挂起的事务
int PROPAGATION_NOT_SUPPORTED = 4;//不支持事务,如果当前上下文中已经存在一个事务,就挂起事务;已非事务的方式执行
int PROPAGATION_NEVER = 5;//不支持事务,如果当前上下文中已经存在一个事务,就抛出异常
int PROPAGATION_NESTED = 6;//如果当前上下文中已经存在事务,就开启一个嵌套的事务。简单来说就是不管当前上下文中是否存在事务,本次都会创建一个事务

  • 隔离级别有4种
int ISOLATION_DEFAULT = -1;//默认的隔离级别,使用数据库当前的隔离级别。会是后面四种隔离级别的其中一种
int ISOLATION_READ_UNCOMMITTED = 1;//读未提交;会有脏读,不可重复读,幻读发生
int ISOLATION_READ_COMMITTED = 2; //读已提交;会有不可重复读,幻读发生
int ISOLATION_REPEATABLE_READ = 4; //重复读;会有幻读出现
int ISOLATION_SERIALIZABLE = 8; //串行化

关于脏读、不可重复读、幻读引用《深入浅出MySQL:数据库开发、优化与管理维护(第2版》中的描述吧

脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。

不可重复读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变或某些记录已经被删除了!这种现象就叫做“不可重复读”。

幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

关于各种隔离级别的描述可以参考我之前的文章隔离性与隔离级别

2. 关于事务属性的默认值,对于springboot来说Transactional注解中定义的。我们可以在定义我们的事务的时候,根据实际需要修改这些属性值

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED;//默认的传播行为

    Isolation isolation() default Isolation.DEFAULT;//默认的隔离级别

    int timeout() default -1;

    String timeoutString() default "";

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

### Spring Boot 中事务传播行为及其用法 #### 什么是事务传播行为事务传播行为定义了一个方法如何参与事务。当调用带有 `@Transactional` 注解的方法时,Spring 根据指定的传播行为决定是否创建新事务或加入现有事务。 常见的事务传播行为有以下几种: - **REQUIRED**: 如果当前存在事务,则加入该事务;如果不存在则创建一个新的事务。 - **REQUIRES_NEW**: 创建一个新的事务,无论当前是否存在事务。如果有当前事务,将其挂起。 - **SUPPORTS**: 如果当前存在事务,则加入该事务;如果没有事务,则以非事务方式执行操作。 - **NOT_SUPPORTED**: 不支持事务上下文,暂停任何现有的事务。 - **MANDATORY**: 当前必须有一个活动的事务,否则抛出异常。 - **NEVER**: 当前不能有任何事务,否则抛出异常。 - **NESTED**: 如果当前存在事务,则在嵌套事务中运行;如果不存在事务,则表现如同 REQUIRED。 这些传播行为可以通过 `propagation` 属性来设置[^2]。 --- #### 使用示例 下面是一个基于不同传播行为的例子,展示它们的行为差异。 ##### 示例代码 假设我们有两个服务类 `ServiceA` `ServiceB`,分别实现不同的业务逻辑并涉及事务处理。 ```java @Service public class ServiceA { @Autowired private ServiceB serviceB; @Transactional(propagation = Propagation.REQUIRED) public void methodInRequired() { System.out.println("Executing in REQUIRED"); serviceB.methodInRequiresNew(); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void methodNotSupported() { System.out.println("Executing without transaction support."); } } @Service public class ServiceB { @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodInRequiresNew() { System.out.println("Executing in REQUIRES_NEW (new transaction)"); } } ``` 在这个例子中: - 方法 `methodInRequired()` 的传播行为为 `REQUIRED`,它会尝试加入已有的事务或者创建新的事务。 - 方法 `methodInRequiresNew()` 的传播行为为 `REQUIRES_NEW`,即使被其他事务中的方法调用,也会启动自己的独立事务。 - 方法 `methodNotSupported()` 则完全不使用事务支持。 --- #### 运行流程分析 1. 调用 `serviceA.methodInRequired()` 时,由于其传播行为为 `REQUIRED`,因此会开启一个事务。 2. 接着调用了 `serviceB.methodInRequiresNew()`,因为它的传播行为为 `REQUIRES_NEW`,所以会在原有事务的基础上挂起当前事务,并创建一个新的事务。 3. 完成后返回到原来的事务继续执行剩余部分。 对于 `methodNotSupported()`,尽管可能处于某个事务范围内,但它不会参与到事务管理之中。 --- #### 数据库交互与事务控制 实际应用中,事务不仅依赖于 Java 层面的配置,还需要底层数据库的支持。例如,在 MySQL 中启用事务模式通常需要调整隔离级别以及关闭自动提交功能[^3]。 以下是手动设置事务参数的一个简单案例: ```java @Transactional(isolation = Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED) public void updateData(String dataId) throws Exception { try { // 执行更新操作 repository.update(dataId); // 模拟错误情况 if ("error".equals(dataId)) { throw new RuntimeException("Simulated error occurred!"); } } catch (Exception e) { log.error("Transaction rolled back due to exception", e); throw e; // 确保回滚发生 } } ``` 在此处设置了较高的隔离等级 (`SERIALIZABLE`) 来防止并发问题,同时也指定了默认的传播行为 `REQUIRED`。 --- #### 总结 通过合理选择组合各种事务传播行为,可以灵活应对复杂的业务需求。每种传播行为都有特定的应用场景,开发者应根据实际情况权衡选用合适的选项。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值