Spring事务管理的全解析

 更新时间:2026年02月11日 08:49:57   作者:NE_STOP  
在一个业务流程中,需要多条DML(insert、delete、update)语句联合才能完成,本文介绍了Spring事务管理的各个方面,感兴趣的朋友跟随小编一起看看吧

事务支持

什么是事务?

在一个业务流程中,需要多条DML(insert、delete、update)语句联合才能完成。这些语句必须同时成功或者同时失败。这样才能保证数据安全。

多条DML同时成功或者同时失败,叫做事务。

事务处理的四个过程

  • 开启事务
  • 执行业务代码
  • 提交事务(没出现异常,提交成功。commit transaction)
  • 回滚事务(出现异常。执行回滚事务. rollback transaction)

事务的四个特性(ACID)

  • A原子性:事务是最小的工作单元,不可分
  • C一致性:事务要么同时成功,要么同时失败
  • I隔离性:事务与事务之间保证和互不干扰
  • D持久性:持久性是事务结束的标志。

spring对事务的支持

spring实现事务的2种方式:

  • 编程式事务:通过编写代码的方式来实现事务管理
  • 声明式事务:基于注解方式和基于xml方式(推荐使用)

spring事务管理api

spring对事务的管理是基于aop实现的。所以spring专门针对事务开发了一套api,其核心接口如下:PlatformTransactionManager 接口。

声明式事务基于注解方式实现

需要配置xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd" >
<!--    组件扫描-->
    <context:component-scan base-package="com.ali" />
<!--    配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/bank"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    </bean>
<!--    配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    开启事务注解驱动器,开启事务注解,需要加上tx的命名空间-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

可以在类和方法上加@Transactional 开启事务

  • 加在类上表示这个类上的所有方法都开启事务
  • 加在方法方法上表示只有这个方法开启事务

事务的传播行为

什么是事务的传播行为?

在service种有a()和b()2个方法,a()上有事务,b()上也有事务,当a()在执行过程中调用了b(),事务是如何传递的?是合并到一个事务?还是开启一个新事务?这就是事务的传播行为。

一共有7种传播行为:

  • REQUIRD:支持当前事务,如果不存在就新建一个事务(默认)【没有就新建,有就加入】
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行【有就加入,没有就不管了】
  • MANDATORY:必须运行在一个事务中,如果当前没有事务发生,将抛出异常【有就加入,没有就抛异常】
  • REQUIRES_NEW:开启一个新事务,如果一个事务已经存在,则将这个存在的事务挂起【不管有没有。直接开启一个新事务。新事务和旧事务不存在嵌套关系,旧事务被挂起了】
  • NOT_SUPPORTED:以非事务方式运行。如果有事务。则挂起当前事务【不支持事务,存在就挂起】
  • NEVER:以非事务方式运行。如果有事务。则抛异常【不支持事务,存在就抛异常】
  • NESTED:如果当前有一个事务在进行中,则该方法应当运行在一个嵌套事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在。行为就像REQUIRD一样【有事务的话,就在这个事务里嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRD一样】

在代码中设置事务的传播行为:

@Transactional(propagation = Propagation.MANDATORY)

事务隔离级别

数据库中读取数据存在三大问题:

  • 脏读:读取到没有提交到数据库的数据
  • 不可重复读:在同一个事务中,第一次和第二次读取的数据不一样
  • 幻读:读到的数据是假的()

事务的隔离级别有4个:

  • 读未提交READ_UNCOMMITTED: 存在脏读、不可重复读、幻读问题
  • 读提交READ_COMMITTED:事务提交之后才读到。存在不可重复读、幻读问题
  • 可重复读REPEATABLE_READ:解决不可重复读的问题,存在幻读问题
  • 序列化SERIALIZABLE:解决幻读问题,事务排队执行。不支持并发。

MySQL默认可重复读,Oracle默认读提交

仅在读的事务中设置隔离级别就行,写的事务没必要设置

代码中设置事务的隔离级别:

@Transactional(isolation = Isolation.DEFAULT)

事务超时

@Transactional(timeout = 10)

以上代码设置事务超时时间为10s

表示超过10s,如果事务中所有的DML语句还没有执行完毕的话,最终结果会回滚。

默认值-1,表示没有时间限制。

事务的超时时间值得是哪段时间?

在当前事务中,最后一条DML语句执行之前的时间,如果最后一条DML语句后面有很多业务逻辑,这些业务代码执行的时间不被计入超时时间。

只读事务

@Transactional(readOnly = true)

将当前事务设为只读事务,在该事务中只允许执行select 语句。

该特性的作用是:启动spring的优化策略。提高select语句的执行效率。

设置哪些异常回滚事务

@Transactional(rollbackFor = RuntimeException.class)

表示发生RuntimeException异常或该异常的子类异常才回滚

设置哪些异常不回滚事务

@Transactional(noRollbackFor = NullPointerException.class)

表示发生NullPointerException异常或该异常的子类不回滚,其他异常才回滚

事务的全注解式开发

编写配置类

@Configuration // 代替xml配置文件
@ComponentScan("com.ali") // 扫描com.ali包下的所有类
@EnableTransactionManagement // 开启事务管理
public class Spring6Config {
    // @Bean注解用于将方法的返回值注册为Spring容器中的一个Bean
    @Bean(name = "druidDataSource")
    public DruidDataSource druidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring6?useSSL=false&serverTimezone=UTC");
        druidDataSource.setUsername("root");
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setPassword("123456");
        return druidDataSource;
    }
    @Bean(name = "transactionManager")
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
    @Bean(name = "jdbcTemplate")
    // 该方法的参数DataSource dataSource会自动从Spring容器中找到类型为DataSource的Bean并注入
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
}

使用时和其他方式一样。

到此这篇关于Spring事务管理的文章就介绍到这了,更多相关spring事务管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中Parser的用法

    Java中Parser的用法

    这篇文章主要介绍了Java Parser使用指南,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • java操作hdfs的方法示例代码

    java操作hdfs的方法示例代码

    这篇文章主要介绍了java操作hdfs的相关资料,在本地配置Hadoop和Maven的环境变量,首先需从官网下载与服务器相同版本的Hadoop安装包,配置环境变量后,引入Maven的配置文件,以便管理项目依赖,最后,编写代码实现对HDFS的连接和操作,完成数据的读写,需要的朋友可以参考下
    2022-02-02
  • Java多线程中ThreadLocal解读

    Java多线程中ThreadLocal解读

    这篇文章主要介绍了Java多线程中ThreadLocal解读,  多线程访问同一个共享变量的时候容易出现并发问题,因此为了保证线程安全性,我们都会采用加锁的方式,而ThreadLocal是除加锁方式之外的另一种保证线程安全性的方法,需要的朋友可以参考下
    2023-09-09
  • MyBatis属性名和字段名不一致的问题解决方法

    MyBatis属性名和字段名不一致的问题解决方法

    这篇文章给大家详细介绍了MyBatis属性名和字段名不一致的问题解决,文中有详细的代码示例和图文展示供大家参考,对大家的学习或工作有一定的参考价值,需要的朋友可以参考下
    2023-12-12
  • Springboot整合junit过程解析

    Springboot整合junit过程解析

    这篇文章主要介绍了Springboot整合junit过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • 使用IDEA如何拉取GitLab项目

    使用IDEA如何拉取GitLab项目

    使用IDEA拉取GitLab项目,首先需要组长提供的socket和账号密码登录内网的GitLab,打开IDEA,选择新建项目,选择Project from Version Control,然后在项目路径后面添加.git,以上步骤为个人操作经验,希望能为大家提供参考
    2024-10-10
  • Java报错Java.net.SocketTimeoutException的几种解决方法

    Java报错Java.net.SocketTimeoutException的几种解决方法

    在 Java 网络编程中,SocketTimeoutException 通常表示在进行网络操作时,等待响应的时间超过了设定的超时时间,本文将深入探讨 Java.net.SocketTimeoutException 的问题,并为开发者和环境配置者提供详细的解决方案,需要的朋友可以参考下
    2024-10-10
  • 深入浅析Netty 在 Dubbo 中是如何应用的

    深入浅析Netty 在 Dubbo 中是如何应用的

    国内知名框架 Dubbo 底层使用的是 Netty 作为网络通信,那么内部到底是如何使用的呢?今天通过本文给大家详细讲解,对Netty 在 Dubbo中应用相关知识感兴趣的朋友跟随小编一起看看吧
    2020-05-05
  • SpringBoot详解自定义Stater的应用

    SpringBoot详解自定义Stater的应用

    Springboot的出现极大的简化了开发人员的配置,而这之中的一大利器便是springboot的starter,starter是springboot的核心组成部分,springboot官方同时也为开发人员封装了各种各样方便好用的starter模块
    2022-07-07
  • Hibernatede 一对多映射配置方法(分享)

    Hibernatede 一对多映射配置方法(分享)

    下面小编就为大家带来一篇Hibernatede 一对多映射配置方法(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09

最新评论