Spring 的事务了解吗?

Spring 的事务一直是面试官经常询问的一个话题,但很多人只知道 @ Transactional 这个注解,但对 Spring 的事务体系,实现方式等方面却知之甚少,本文就将以图文结合的方式向读者介绍关于 Spring 事务。

什么是事务?

事务是逻辑上的一组操作,要么都执行,要么都不执行。

在 MySQL 数据库中只有 InnoDB 引擎才支持事务。

事务的 ACID 特性

原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。

一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的。

隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。

持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的。

Spring 支持事务的两种方式

1)编程式事务:在代码中硬编码(不推荐使用) : 通过  TransactionTemplate 的 execute 或者 TransactionManager 的 commit 和 rollback 手动管理事务,实际应用中很少使用,但是对于你理解 Spring 事务管理原理有帮助。2)声明式事务:在 XML 配置文件中配置或者直接基于注解(推荐使用) : 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)

事务属性介绍

事务属性包含了 5 个方面

1)隔离级别

2)传播行为

3)回滚规则

4)是否只读

5)事务超时

隔离级别

隔离级别默认和数据库是一致的,一般不需要进行改动。

package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface TransactionDefinition {
    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;
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
    int TIMEOUT_DEFAULT = -1;
    // 返回事务的传播行为,默认值为 REQUIRED。
    int getPropagationBehavior();
    //返回事务的隔离级别,默认值是 DEFAULT
    int getIsolationLevel();
    // 返回事务的超时时间,默认值为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
    int getTimeout();
    // 返回是否为只读事务,默认值为 false
    boolean isReadOnly();

    @Nullable
    String getName();
}
传播行为

1)TransactionDefinition.PROPAGATION_REQUIRED

如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

举个例子:

如果只要 A 或者 B 任意一个方法有异常,那么整个事务都会回滚。

@Service
Class A {
    @Autowired
    B b;
    @Transactional(propagation = Propagation.REQUIRED)
    public void aMethod {
        b.bMethod();
    }
}
@Service
Class B {
    @Transactional(propagation = Propagation.REQUIRED)
    public void bMethod {
    }
}

2)TransactionDefinition.PROPAGATION_REQUIRES_NEW

创建一个新的事务,如果当前存在事务,则把当前事务挂起。

举个例子:

B 事务开启了独立的事务,如果 A 抛出异常回滚,B 不会回滚,但 B 如果抛出异常回滚,那么 A 会回滚。

@Service
Class A {
    @Autowired
    B b;
    @Transactional(propagation = Propagation.REQUIRED)
    public void aMethod {
 
        b.bMethod();
    }
}

@Service
Class B {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void bMethod {
  
    }
}

3)TransactionDefinition.PROPAGATION_NESTED

如果当前存在事务,就在嵌套事务内执行;如果当前没有事务,就单独开启一个事务。

举个例子:

当 A 回滚,B 是嵌套事务,会跟着一起回滚。当 B 回滚,A 不会跟着回滚。

@Service
Class A {
    @Autowired
    B b;
    @Transactional(propagation = Propagation.REQUIRED)
    public void aMethod {
        b.bMethod();
    }
}

@Service
Class B {
    @Transactional(propagation = Propagation.NESTED)
    public void bMethod {
    }
}

4)TransactionDefinition.PROPAGATION_MANDATORY

如果当前存在事务就加入该事务,如果当前没有事务,就抛出异常。

5)TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式继续运行。

6)TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

7)TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

事务回滚规则

默认情况下,只有遇到运行时异常 RuntimeException 的子类才会回滚,Error 也会导致事务回滚。

可以指定要回滚的异常类型

@Transactional(rollbackFor= BusinessException.class)

介绍一下 @Transactional 的作用范围

1)方法(只对 Public 方法生效)

2)类(整个类的 Public 方法都生效)

3)接口(不推荐)

是否只读

readOnly,指定事务是否为只读事务,默认为 false。用来优化事务的执行,默认情况下每一个 SQL 放入单独的事务,事务要提交多次,如果声明了只读事务的话,数据库就会去优化它的执行。

事务超时

timeout 指定事务的超时时间,默认为-1(永远不会超时回滚),指定后超过时间会自动回滚。

注意事项:同类方法自调用会让 AOP 的代理模式失效。因此事务会失效。

其他补充

  1. 事务的基本概念:

    • 事务是一组操作,被视为一个不可分割的工作单元,要么全部执行成功,要么全部失败回滚。

    • Spring 通过 PlatformTransactionManager 接口实现事务管理,支持不同的事务管理器,如 JDBC、Hibernate、JTA 等。

  2. 隔离级别(Isolation Levels):

    • DEFAULT: 使用数据库默认的隔离级别。

    • READ_UNCOMMITTED: 允许读取尚未提交的更改。

    • READ_COMMITTED: 允许只读取已提交的更改。

    • REPEATABLE_READ: 对相同字段的多次读取返回相同的结果,除非进行更新操作。

    • SERIALIZABLE: 最高的隔离级别,确保事务之间完全隔离。

    • 事务隔离级别定义了一个事务可能受其他并发事务影响的程度。

    • Spring 支持数据库的四种隔离级别:

  3. 传播行为(Propagation Behavior):

    • 事务传播行为定义了方法在一个事务内执行时,如果有另一个事务存在,应该如何处理。

    • 例如,REQUIRED 表示如果当前存在事务,则加入该事务,否则创建一个新的事务。

    • 一些传播行为:REQUIREDSUPPORTSMANDATORYREQUIRES_NEWNOT_SUPPORTEDNEVERNESTED

  4. 超时时间(Timeout):

    • 超时时间定义了事务的最大执行时间。如果事务执行时间超过设定的超时时间,将被强制回滚。

    • 超时时间通过 @Transactional 注解的 timeout 属性设置,单位是秒。

  5. 回滚规则(Rollback Rules):

    • 回滚规则定义了哪些异常触发事务回滚。可以通过 @Transactional 注解的 rollbackFor 和 noRollbackFor 属性进行设置。

    • rollbackFor 指定哪些异常触发回滚,noRollbackFor 指定哪些异常不触发回滚。

  6. 是否只读(Read-Only):

    • 设置事务是否为只读可以提高性能,因为只读事务不需要写入操作的事务支持。

    • 可以通过 @Transactional 注解的 readOnly 属性设置,表明事务是否为只读事务。

示例:

@Transactional(
    isolation = Isolation.READ_COMMITTED,
    propagation = Propagation.REQUIRED,
    timeout = 30,
    rollbackFor = {SQLException.class},
    readOnly = true
)
public void myTransactionalMethod() {
    // 事务处理逻辑
}

这是一个简单的例子,实际使用时根据具体情况选择合适的隔离级别、传播行为、超时时间、回滚规则和只读属性。

七种传播行为

图片

推荐文章和书籍

Spring 官方文档:https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html

书籍:《Spring 实战 第五版》

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Ale-阿乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值