当前位置: 首页 > news >正文

Spring事务管理详解(传播属性、隔离级别)

(一)事务的概述

事务指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务在数据库的增删改操作中最为常见。事务具有ACID的特性,即原子性、一致性、隔离性、持久性。通过JDBC首先来了解一下事务的运行原理:

(二)JDBC中的事务

事务的操作主要由三大模块,即事务的开启、事务的提交和事务的回滚。

首先写一段jdbc操作事务的代码,这里用到的数据库名为user,只有name和age两个属性:

1.创建连接工具类:

public class ConnectionUtil {
    public final static String DB_DRIVER="com.mysql.jdbc.Driver";
    public final static String DB_URL="jdbc:mysql://localhost:3306/transactiontest";
    public final static String DB_USER="root";
    public final static String DB_PWD="123456";
    public static Connection getConnection() throws ClassNotFoundException, SQLException {
        Connection conn=null;
        Class.forName(DB_DRIVER);
        conn= DriverManager.getConnection(DB_URL,DB_USER,DB_PWD);
        System.out.println("数据库连接成功");
        return conn;
    }
}

2.JDBC操作数据库:

public class TransactionTest1 {
    public static void main(String[] args) {
        Connection conn=null;
        try {
            conn=ConnectionUtil.getConnection();
            //1.开启事务
            conn.setAutoCommit(false);
            insertTest1(conn);
            //2.提交事务
            conn.commit();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                //3.事务的回滚
                conn.rollback();
                System.out.println("rollback success");
            } catch (SQLException ex) {
                System.out.println("rollback failed");
            }
        }finally {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    private static void insertTest1(Connection conn) throws SQLException {
        PreparedStatement stat=conn.prepareStatement("insert into user(name) values (?)");
        stat.setString(1,"sdxb");
        stat.executeUpdate();
        System.out.println("insert success");
        stat.close();
    }
}

代码第七行关闭自动提交表示事务的开启位置,进行一系列操作后(增删改查),事务提交。如果此时没有报错,事务提交成功,业务完成。如果此时出现报错,就会进入事务的回滚,回到最初的状态,维持事务的一致性。

(三)Spring中的事务

Spring实现事务的方式有两种,编程式事务管理声明式事务管理

编程式事务管理在Spring中有两种实现方式:使用TransactionTemplate和直接使用PlatformTransactionManager。

声明式事务管理的其中一个代表就是@Transactional 注解,随着Spring更新中逐步抛弃了配置文件的使用,使用@Transactional注解管理事务成了很常用的方式。

@Transactional注解的使用很简单,在需要添加事务的方法上增加@Transactional注解

@Transactional的参数如下所示

参数名称

功能描述

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")

指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")

指定多个异常类名称:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

在@Transactional的参数中,尤其需要注意的是传播属性(propagation)和隔离级别(isolation):

(四)Spring事务的传播属性

事务的传播属性只在Spring中存在,在数据库中的事务中不存在传播属性的说法

Spring的传播属性有以下七种:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。(默认)

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

4.1 重要传播属性的解释:

假设有ServiceA.MethodA(),在其内部调用ServiceB.MethodB()

PROPAGATION_REQUIRED

Spring默认使用PROPAGATION_REQUIRED传播属性,当ServiceA.MethodA()运行时,开启一个事务,此时ServiceB.MethodB()方法发现已经存在一个事务,就不会再开启事务,因此不管哪一个方法报错,都会回调。

PROPAGATION_REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。当ServiceA.MethodA()运行时,开启一个事务A。当运行ServiceB.MethodB()时,把事务A挂起,然后开启事务B。就算事务A发生回滚,事务B依然能正常提交。总结起来就是:外部事务不会影响内部事务的提交和回滚。

PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行。关于嵌套需要首先了解检查点的概念:当在事务中设置检查点后,如果发生回滚,会回滚到设置检查点的位置,而不是回滚整个事务。嵌套事务就使用了检查点Savepoint。当ServiceA.MethodA()运行时,开启一个事务A。当运行ServiceB.MethodB()时,开启一个子事务B,它将取得一个 savepoint. 如果这个事务B失败, 将回滚到此 savepoint,而不会影响整个事务。总结一句话就是内部事务不会影响外部事务的提交和回滚

(五)Spring事务的隔离级别

首先了解一下三种数据库中可能会发生的三种问题:

脏读:一个事务读到另一个事务未提交的更新数据

不可重复读 : 前后多次读取,数据内容不一致

幻读: 前后多次读取,数据总量不一致

Spring的隔离级别:

1.  ISOLATION_DEFAULT: 这是一个 PlatfromTransactionManager  默认的隔离级别,使用数据库默认的事务隔离级别.

2.  ISOLATION_READ_UNCOMMITTED:读未提交。这是事务最低的隔离级别,这种隔离级别会产生脏读,不可重复读和幻像读。

3. ISOLATION_READ_COMMITTED读已提交,ORACLE默认隔离级别,有幻读以及不可重复读风险。

4. ISOLATION_REPEATABLE_READ: 可重复读,解决不可重复读的隔离级别,但还是有幻读风险。

5. ISOLATION_SERIALIZABLE  串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,解决脏读、不可重复读和幻读。

隔离级别并非越高越好,越高的隔离级别意味着越大的资源消耗,因此需要做适当取舍。

相关文章:

  • 5分钟学会使用Less预编译器
  • RabbitMQ学习系列(一):RabbitMQ的了解安装和使用
  • RabbitMQ学习系列(二):简单队列详解
  • spring学习笔记(4)依赖注入详解
  • RabbitMQ学习系列(三):工作队列详解
  • RabbitMQ学习系列(四):发布-订阅模型详解
  • Android进阶学习
  • RabbitMQ学习系列(五):routing路由模式和Topic主题模式
  • RabbitMQ学习系列(六):RabbitMQ消息确认机制
  • cisco 交换机自动备份配置
  • 应届毕业生因为疫情休息在家,可以通过哪些途径提高自己?
  • APP产品交互设计分析总结(不断更新中...)
  • 以SpringBoot作为后台实践ajax异步刷新
  • 观察:阿里的VR实验室能解决什么问题?
  • JavaIO详解--JavaIO的整体结构以及File类的使用
  • iOS 系统授权开发
  • Mysql数据库的条件查询语句
  • PaddlePaddle-GitHub的正确打开姿势
  • Redis 懒删除(lazy free)简史
  • scrapy学习之路4(itemloder的使用)
  • Spring声明式事务管理之一:五大属性分析
  • 三分钟教你同步 Visual Studio Code 设置
  • 设计模式(12)迭代器模式(讲解+应用)
  • 手机端车牌号码键盘的vue组件
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • ​香农与信息论三大定律
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (C++二叉树05) 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (补充)IDEA项目结构
  • (第27天)Oracle 数据泵转换分区表
  • (分布式缓存)Redis持久化
  • .cfg\.dat\.mak(持续补充)
  • .gitignore
  • .Net 6.0 Windows平台如何判断当前电脑是否联网
  • .NET gRPC 和RESTful简单对比
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET/C# 使用反射注册事件
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .net通用权限框架B/S (三)--MODEL层(2)
  • .NET运行机制
  • .NET中的Exception处理(C#)
  • .project文件
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • @EnableWebMvc介绍和使用详细demo
  • @Slf4j idea标红Cannot resolve symbol ‘log‘
  • @TableLogic注解说明,以及对增删改查的影响
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • [ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)