Spring—事务及事务的传播机制

这篇具有很好参考价值的文章主要介绍了Spring—事务及事务的传播机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

🔎事务的定义


将一组操作封装成一个执行单元, 即这一组操作一同成功 / 一同失败

举个栗子🌰

未使用事务

滑稽老哥给女神转账 520
由于某种原因, 女神并未收到转账的 520, 而滑稽老哥却被扣款 520

使用事务

滑稽老哥给女神转账 520
由于某种原因, 女神并未收到转账的 520
因为使用事务, 所以滑稽老哥的钱也被重新打回账户上
(一同成功 / 一同失败)

🔎Spring—事务的实现


Spring—事务的实现有 2 种方式

  1. 通过代码的方式手动实现事务(即 Spring 编程式事务)
  2. 通过注解的方式实现事务(即 Spring 声明式事务)

铺垫


后续内容针对数据表 userinfo 进行演示🍂

-- 创建用户表
drop table if exists userinfo;
create table userinfo(
    id int primary key auto_increment,
    username varchar(100) not null,
    password varchar(32) not null,
    photo varchar(500) default '',
    createtime timestamp default current_timestamp,
    updatetime timestamp default current_timestamp,
    `state` int default 1
) default charset 'utf8mb4';

-- 添加一个用户信息
INSERT INTO `excnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) 
VALUES (1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java


Controller 层(UserController) → Service 层(UserService) → Mapper 层(UserMapper)🍂

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

UserController

代码在 Spring 编程式事务

UserService

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public Integer add(UserInfo userInfo) {
        return userMapper.add(userInfo);
    }

}

UserMapper

@Mapper
public interface UserMapper {

    int add(UserInfo userInfo);

}

UserMapper 对应的 SQL 语句

<insert id="add">
    insert into userinfo(username, password) values(#{username}, #{password})
</insert>

UserInfo

@Data
public class UserInfo {

    private Integer id;
    private String username;
    private String password;
    private String photo;
    private String createtime;
    private String updatetime;
    private Integer state;

}

Spring 编程式事务


Spring 编程式事务与 MySQL 操作事务类似, 分为 3 个部分

  1. 开启事务
  2. 提交事务
  3. 回滚事务
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/add")
    public Integer add(UserInfo userInfo) {
        // 非空校验
        if(userInfo == null || !StringUtils.hasLength(userInfo.getUsername())
        || !StringUtils.hasLength(userInfo.getPassword())) {
            return 0;
        }

        // 1. 开启事务
        TransactionStatus transactionStatus = transactionManager.getTransaction(transactionDefinition);
        // 执行相关业务代码
        int ret = userService.add(userInfo);
        System.out.println("add : " + ret);
        // 2. 提交事务
        transactionManager.commit(transactionStatus);
        // 3. 回滚事务
        transactionManager.rollback(transactionStatus);
        return ret;
    }

}

验证效果(开启事务 + 提交事务)🍂

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

验证效果(开启事务 + 回滚事务)🍂

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

Spring 声明式事务


利用注解 @Transactional 实现 Spring 声明式事务

@Transactional 的特点

  • 可以添加在类 / 方法上(默认情况下 @Transactional 针对的是 public 修饰的方法)
  • 方法执行前自动开启事务, 方法执行期间出现异常 → 自动回滚事务, 方法执行完(无异常) → 自动提交事务

举个栗子🌰

方法执行期间出现异常 → 自动回滚事务

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

方法执行完(无异常) → 自动提交事务

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

@Transactional 的参数


Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

参数 作用
value 配置多个事务管理器时, 可指定需要的事务管理器
transactionManager 配置多个事务管理器时, 可指定需要的事务管理器
propagation 事务的传播行为, 默认值为 Propagation.REQUIRED
isolation 事务的隔离级别, 默认值为 Isolation.DEFAULT
timeout 事务的超时时间, 默认值为 -1, 表示超时时间为无限大, 即事务将一直持续直到完成或手动回滚(如果超出设置的时间限制事务仍未完成, 则自动回滚事务)
readOnly 指定事务是否为只读, 默认值为 false(为了忽略不需要事务的方法, 例如读取数据, 设置 read-only 为 true)
rollbackFor 用于指定能够触发事务回滚的异常类型(可指定多个异常类型)
rollbackForClassName 用于指定能够触发事务回滚的异常类型(可指定多个异常类型)
noRollbackFor 抛出指定的异常类型, 不回滚事务(可指定多个异常类型)
noRollbackForClassName 抛出指定的异常类型, 不回滚事务(可指定多个异常类型)

注意事项


方法内部存在异常, 但被捕获(try-catch)时, 仍会提交事务

即方法执行完(无异常) → 自动提交事务

代码示例如下

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/insert")
    @Transactional
    public Integer insert(UserInfo userInfo) {
        // 非空校验
        if(userInfo == null || !StringUtils.hasLength(userInfo.getUsername())
        || !StringUtils.hasLength(userInfo.getPassword())) {
            return 0;
        }

        int ret = userService.add(userInfo);
        System.out.println("insert : " + ret);

        try {
            int num = 2 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return ret;
    }

}

针对上述情况, 想要回滚事务, 有 2 种解决方式

  1. 继续抛出异常
  2. 手动回滚事务(推荐)

继续抛出异常🍂

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/insert")
    @Transactional
    public Integer insert(UserInfo userInfo) {
        // 非空校验
        if(userInfo == null || !StringUtils.hasLength(userInfo.getUsername())
        || !StringUtils.hasLength(userInfo.getPassword())) {
            return 0;
        }

        int ret = userService.add(userInfo);
        System.out.println("insert : " + ret);

        try {
            int num = 2 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());

            // 抛出异常
            throw e;
        }

        return ret;
    }

}

验证效果(抛出异常)

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

手动回滚事务🍂

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/insert")
    @Transactional
    public Integer insert(UserInfo userInfo) {
        // 非空校验
        if(userInfo == null || !StringUtils.hasLength(userInfo.getUsername())
        || !StringUtils.hasLength(userInfo.getPassword())) {
            return 0;
        }

        int ret = userService.add(userInfo);
        System.out.println("insert : " + ret);

        try {
            int num = 2 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());

            // 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }

        return ret;
    }

}

验证效果(手动回滚事务)

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

@Transactional 的工作原理


@Transactional 是基于 AOP 实现, AOP 使用动态代理实现

目标对象实现了接口, 默认采用 JDK 的动态代理 / 目标对象未实现接口, 默认采用 CGLIB 的动态代理

@Transactional 在开始执行业务之前, 通过代理开启事务, 执行成功之后提交事务(执行期间遇到异常回滚事务)


Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

🔎Spring—事务的隔离级别


事务有 4 大特性(ACID)

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

原子性🍂

定义

⼀个事务(Transaction)中的所有操作, 要么全部完成, 要么全部不完成, 不会结束在中间某个环节. 事务在执⾏过程中发⽣错误, 会被回滚(Rollback)到事务开始前的状态, 就像这个事务从来没有执⾏过⼀样

翻译

用户 A 给用户 B 转账
要么 A 成功转账给 B, B 收到转账的钱
要么 A 没能转账给 B, B 未收到转账的钱
不能出现 A 成功转账给 B, B 未收到钱等类似的情况

一致性🍂

定义

在事务开始之前和事务结束以后, 数据库的完整性没有被破坏. 这表示写⼊的资料必须完全符合所有的预设规则, 这包含资料的精确度, 串联性以及后续数据库可以⾃发性地完成预定的工作

翻译

用户 A 给用户 B 转账 520
A 账户被扣款 520, B 账户增加 520
不能出现 A 账户扣款 1000, B 账户增加 520 等类似的情况

隔离性🍂

定义

数据库允许多个并发事务同时对其数据进⾏读写和修改的能⼒, 隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不⼀致. 事务隔离分为不同级别, 包括读未提交(Read Uncommitted), 读已提交(Read Committed), 可重复读(Repeatable Read)和串行化(Serializable)

翻译(摘抄自网络)

将点餐过程理解为一个事务
制作 → 出餐 → 送餐 → 结算作为一个事务

不同的客户进行点餐是相互独立的, 并不会彼此影响 → 事物的隔离性

当一个事务影响其他事务时, 其他事务将会回滚

今日份的猪脚饭已经全部卖完, 再次点餐将会影响后续事务(制作 → 出餐 → 送餐 → 结算), 此时后续事务将会回滚

持久性🍂

定义

事务处理结束后, 对数据的修改就是永久的, 即便系统故障也不会丢失

翻译

用户 A 执行转账操作, 银行系统会开启事务, 将转账金额从 A 账户扣除, 将对应金额添加至 B 账户
当事务提交成功后, 系统会将更改持久化到数据库
即使系统发生故障, 数据库仍然能够恢复并保持转账操作的结果

MySQL—事务的隔离级别


MySQL—事务的隔离级别🍂

  1. READ UNCOMMITTED → 读未提交
  2. READ COMMITTED → 读已提交
  3. REPEATABLE READ → 可重复读(MySQL 默认的事务隔离级别)
  4. SERIALIZABLE → 串行化
事务隔离级别 脏读 不可重复读 幻读
读未提交(READ UNCOMMITTED)
读已提交(READ COMMITTED)
可重复读(REPEATABLE READ)
串行化(SERIALIZABLE)

Spring—事务的隔离级别


Spring—事务及事务的传播机制,JavaEE,spring,数据库,java


Spring—事务的隔离级别🍂

  1. Isolation.DEFAULT → 以链接数据库的事务隔离级别为主
  2. Isolation.READ_UNCOMMITTED → 读未提交
  3. Isolation.READ_COMMITTED → 读已提交
  4. Isolation.REPEATABLE_READ → 可重复读
  5. Isolation.SERIALIZABLE → 串行化

Spring—设置事务的隔离级别


@Transactional(isolation = Isolation.DEFAULT)
public void setIsolationLevel() {

}

🔎Spring—事务的传播机制


事务的传播机制 → 事务的隔离级别 Plus 版

事务的隔离级别🍂

解决多个事务同时调用数据库的问题

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

事务的传播机制

解决一个事务在多个方法中传递的问题

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

Spring—事务传播机制的分类


Spring—事务传播机制的分类🍂

  1. Propagation.REQUIRED → 默认的事务传播级别. 表示如果当前存在事务, 则加入该事务 / 如果当前不存在事务, 则创建一个新的事务
  2. Propagation.SUPPORTS → 如果当前存在事务, 则加入该事务 / 如果当前不存在事务, 则以非事务方式运行
  3. Propagation.MANDATORY → 如果当前存在事务, 则加入该事务 / 如果当前不存在事务, 则抛出异常
  4. Propagation.REQUIRES_NEW → 表示创建一个新的事务. 如果当前存在事务, 则把当前事务挂起(强制必须有事务)
  5. Propagation.NOT_SUPPORTED → 以非事务方式运行, 如果当前存在事务, 则把当前事务挂起
  6. Propagation.NEVER → 以非事务方式运行, 如果当前存在事务, 则抛出异常
  7. Propagation.NESTED → 如果当前存在事务, 则创建一个事务作为当前事务的嵌套事务运行 / 如果当前不存在事务, 效果等同于 Propagation.REQUIRED

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java


举个栗子🌰

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java


对比加入事务与嵌套事务


Spring—事务及事务的传播机制,JavaEE,spring,数据库,java


UserController

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private LoginService loginService;

    @RequestMapping("/insert")
    @Transactional
    public Integer insert(UserInfo userInfo) {
        // 非空校验
        if(userInfo == null || !StringUtils.hasLength(userInfo.getUsername())
        || !StringUtils.hasLength(userInfo.getPassword())) {
            return 0;
        }

        int ret = userService.add(userInfo);
        if(ret > 0) {
            loginService.add();
        }

        return ret;
    }

}

加入事务🍂

@Transactional(propagation = Propagation.REQUIRED)为例

UserService

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer add(UserInfo userInfo) {
        int ret = userMapper.add(userInfo);
        System.out.println("添加 : " + ret);
        return ret;
    }

}

LoginService

@Service
public class LoginService {

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer add() {
        try {
            int num = 1 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return -1;
    }

}

验证效果(执行期间出现异常 → 回滚全部事务)

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

嵌套事务🍂

@Transactional(propagation = Propagation.为例

UserService

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.NESTED)
    public Integer add(UserInfo userInfo) {
        int ret = userMapper.add(userInfo);
        System.out.println("添加 : " + ret);
        return ret;
    }

}

LoginService

@Service
public class LoginService {

    @Transactional(propagation = Propagation.NESTED)
    public Integer add() {
        try {
            int num = 1 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return -1;
    }

}

验证效果(执行期间出现异常 → 回滚部分事务)

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java

总结加入事务与嵌套事务之间的区别


加⼊事务(REQUIRED) 和 嵌套事务(NESTED) 的区别

  • 整个事务如果全部执行成功,结果均相同
  • 如果事务执行期间失败了, 那么加入事务会将整个事务全部回滚;嵌套事务则会局部回滚,不会影响上⼀个方法中执行的结果

🌸🌸🌸完结撒花🌸🌸🌸

Spring—事务及事务的传播机制,JavaEE,spring,数据库,java文章来源地址https://www.toymoban.com/news/detail-546004.html

到了这里,关于Spring—事务及事务的传播机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring的事务传播机制

    嫌弃内容代码复杂的可直接看思维导图大纲即可 指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行 默认,当前存在事务,则加入该事务;不存在事务,创建新事务。 始终以新的事务运行,当前存在事务,则挂起原事务;不存在事务,创建新事务

    2023年04月23日
    浏览(52)
  • Spring事务传播机制

    编程式事务管理:通过  TransactionTemplate 或者 TransactionManager 手动管理事务,实际应用中很少使用,这不是本文的重点,就不在这里赘述。 声明式事务管理:使用场景最多,也是最推荐使用的方式,直接加上@Transactional注解即可。 @Transactional 注解是用于声明事务性方法的注解

    2024年01月16日
    浏览(38)
  • Spring事务传播机制解析

    在Java的Spring框架中,事务管理是保证应用数据一致性和可靠性的关键。Spring提供了灵活的事务传播机制,它定义了事务边界,以及在嵌套方法调用时如何处理事务。本文旨在深入探讨Spring的事务传播行为,帮助开发者更好地理解和运用这一重要特性。 事务传播机制指的是在

    2024年01月16日
    浏览(38)
  • 【Spring】深入理解 Spring 事务及其传播机制

    在 Spring 框架中,事务(Transaction)是一种用于管理数据库操作的机制,旨在 确保数据的 一致性、可靠性和完整性 。事务可以将一组数据库操作(如插入、更新、删除等)视为一个单独的执行单元,要么 全部成功地执行,要么全部回滚 。这样可以确保数据库在任何时候都保

    2024年02月12日
    浏览(61)
  • Spring Boot 事务和事务传播机制

    事务定义 将一组操作封装成一个执行单元 (封装到一起),这一组的执行具备原子性, 那么就要么全部成功,要么全部失败. 为什么要用事务? 比如转账分为两个操作: 第一步操作:A 账户-100 元。 第二步操作:B账户 +100 元。 如果没有事务,第一步执行成功了,第二步执行失败了,

    2024年02月11日
    浏览(38)
  • Spring事务的四大特性+事务的传播机制+隔离机制

    原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 事务是一个原子操作, 由一系列动作组成。 组成一个事务的多个数据库操作是一个不可分割的原子单元 ,只有所有的操作执行成功,整个事务才提交。 事务中的任何一个数据库操作失败

    2024年01月20日
    浏览(40)
  • 一文详解Spring事务传播机制

    目录 背景 Spring事务 @Transactional注解 使用场景 失效场景 原理 常用参数 注意 事务传播机制 处理嵌套事务流程 主事务为REQUIRED子事务为REQUIRED 主事务为REQUIRED子事务为REQUIRES_NEW 主事务为REQUIRED子事务为NESTED 实现方式 源码解析 我们在使用Spring管理数据库事务的时候很方便,只

    2023年04月26日
    浏览(48)
  • Spring @Transactional事务传播机制详解

    我们日常工作中极少使用事务传播级别,单纯只是使用事务和rollbackfor抛出异常来解决事务问题,但其实我们很多时候使用的是不正确的,或者说会造成事务粒度过大,本文详解一下事务传播级别,也让自己更好地处理事务问题。 1.什么是事务传播机制? 举个栗子,方法A是一

    2024年02月14日
    浏览(43)
  • Spring事务传播的7种机制

    1. Propagation.REQUIRED:默认的事务传播级别,它表示如果当前存在事务,则加入该事务;如果 当前没有事务,则创建一个新的事务。 2. Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的 方式继续运行。 3. Propagation.MANDATORY:(mandatory:强制

    2024年02月09日
    浏览(47)
  • spring事务管理详解和实例(事务传播机制、事务隔离级别)

    目录 1 理解spring事务 2 核心接口 2.1 事务管理器 2.1.1 JDBC事务 2.1.2 Hibernate事务 2.1.3 Java持久化API事务(JPA) 2.2 基本事务属性的定义 2.2.1 传播行为 2.2.2 隔离级别 2.2.3 只读 2.2.4 事务超时 2.2.5 回滚规则 2.3 事务状态 3 编程式事务 3.1 编程式和声明式事务的区别 3.2 如何实现编程式

    2024年02月06日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包