Spring事务及事务传播机制(2)

@Transactional详解

我们主要学习@Transactional注解当中的三个常见属性:

1.rollbackFor: 异常回滚特性. 指定能够触发事务回滚的异常类型. 可以指定多个异常类型.

2.Isolation:事务的隔离级别. 默认值为Isolation.DEFAULT

3.propagation: 事务的传播机制. 默认为Propagation.REQUIRED.

rollbackFor

@Transactional 默认只在遇到运行时异常和Error才会进行回滚, 非运行时异常不回滚. 即Exception的子类中, 除了RuntimeException及其子类.

之前我们通过制造一个运行时异常, 发现事务回滚了, 接下来把异常改为如下代码:

java 复制代码
    @Transactional
    @RequestMapping("/registry")
    public String registry(String name, String password) throws IOException {
        //用户注册
        userService.registryUser(name, password);
        log.info("用户数据插入成功");
        if(true) {
            throw new IOException();
        }
        return "注册成功";
    }

运行程序:

发现虽然程序抛出了异常, 但是事务仍被提交:

如果需要所有的异常都回滚, 需要配置@Transactional注解当中的rollbackFor属性, 通过rollbackFor这个属性指定出现何种异常类型时事务进行回滚.

java 复制代码
@Transactional(rollbackFor = Exception.class)

运行代码, 观察现象:

发现这时事务进行了回滚.

结论:

在Spring事务管理中, 默认只在遇到运行时异常RuntimeException和Error时才会进行回滚.

如果需要回滚指定类型的异常, 可以通过rollbackFor属性来指定.

事务隔离级别

回顾: 并发读数据库可能引发的问题

1.脏读:指一个事务A读取到了事务B还没有提交的数据, 在之后事务B进行了修改, 这时候事务A读到的数据称为脏数据, 也叫脏读.(解决方案: 给写操作加锁, 即一个事务在没有提交之前, 不能被读取).

2.不可重复读**: 一个事务先后两次读取到的数据不一致, 可能是两次读取过程中插入了一个新的事务更新了原有的数据, 注:侧重于修改**(解决方案: 给读操作加锁, 即一个事务在没有读完的时候不会插入其它的数据).

3.幻读: 同一个事务中, 多次查询的结果集返回不一致 . 比如事务A查询了几列数据, 而事务B在此时又插入了新的几列数据(注:侧重于新增或删除),先前的事务在接下来的查询中, 就会发现几列是它先前所没有的, 这就是幻读. (解决方案: 进一步提高事务之间的隔离性, 即串行化).

MySQL数据库事务隔离级别

1.读未提交: 最低的隔离级别, 在该级别内可以看到其它事务未提交的数据.

因为其它未提交的数据可能会发生回滚, 但是在该级别下仍然是可以读到的, 这个读到的就是脏数据.

2.读已提交: 在该级别内, 一个事务只能读取其它事务中已提交的数据(相当于加写锁).

在该隔离级别内不会存在脏读的问题. 但由于在事务的执行中可以读取到其它事务提交的结果, 所以在不同时间读取到的数据可能不一致.

3.可重复读: 事务不会读到其它事务对已有数据的修改, 即使其它事务已经提交. 也就可以确保同一事务多次查询到的结果一致, 但是对于其它事务新插入的数据, 是可以感知到的. 这就引发了幻读问题. 可重复读, 是MySQL中默认的事务隔离级别(相当于加读锁和写锁).

比如此级别的事务正在执行时, 另一个事务中新增了一条数据, 但是由于每次读取的时候结果都一样, 所以导致查询不到这条数据.

4.串行化: 是事务的最高隔离级别, 它会强制事务排序, 使之不会发生冲突. 但是因为资源消耗很大, 所以不太常用.

Spring中的事务隔离级别:

1.Isolation.DEFAULT: 以连接的数据库的隔离级别为主.

2.Isolation.READ_UNCOMMITTED:读未提交

3.Isolation.READ_COMMITED: 读已提交.

4.Isolation.REPEATABLE_READ: 可重复读

5.Isolation.SERIALIZABLE: 串行化.

spring中的事务隔离级别也可以通过类似之前的rollbackFor的方式设置:

java 复制代码
@Transactional(isolation = Isolation.READ_COMMITTED)

Spring事务传播机制

什么是事务传播机制

事务传播机制就是: 多个事务方法存在调用关系时, 事务是如何在这些方法间进行传播的.

比如有两个方法A, B都被@Transactional修饰, A方法调用B方法, 此时B方法运行时, 是加入A的事务, 还是创建一个新的事务呢?

这就涉及到了事务的传播机制.

事务隔离级别解决的是多个事务同时调用一个数据库的问题.

而事务传播机制解决的hi一个事务在多个节点(方法)中传递的问题

事务的传播机制有哪些?

@Transactional注解支持事务传播机制的设置, 通过propagation属性来指定传播行为.

Spring事务传播机制有以下7种(以下结合一对新人要结婚的例子来说明):

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.(如果有房, 则以房子为根据地, 做点下生意.)

相关推荐
喵叔哟6 分钟前
重构代码中引入外部方法和引入本地扩展的区别
java·开发语言·重构
尘浮生12 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
六月闻君26 分钟前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
SelectDB技术团队35 分钟前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
不是二师兄的八戒36 分钟前
本地 PHP 和 Java 开发环境 Docker 化与配置开机自启
java·docker·php
爱编程的小生1 小时前
Easyexcel(2-文件读取)
java·excel
inventecsh1 小时前
mongodb基础操作
数据库·mongodb
白云如幻1 小时前
SQL99版链接查询语法
数据库·sql·mysql
带多刺的玫瑰1 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
爱吃烤鸡翅的酸菜鱼1 小时前
MySQL初学之旅(4)表的设计
数据库·sql·mysql·database