【spring 事务】事务的基本使用,事务隔离级别、事务传播机制

news2025/1/23 12:08:30

在Spring框架中,声明式事务管理是一种通过注解或配置文件自动管理事务的方式,而不需要手动编写事务管理代码。@Transactional是Spring提供的一个注解,用于声明式事务管理,它使得事务的管理变得简单而清晰。

主要特性

  1. 自动事务管理:使用@Transactional注解时,Spring会自动为相关方法开启、提交和回滚事务。
  2. 事务的传播行为:Spring事务支持多种传播行为,控制方法之间如何共享事务。例如:REQUIRED(默认值),REQUIRES_NEWNESTED等。
  3. 事务的隔离级别:Spring事务支持多种隔离级别,如READ_COMMITTEDREAD_UNCOMMITTEDSERIALIZABLE等,用于定义不同事务之间的隔离程度。
  4. 事务的回滚规则:可以配置在发生哪些异常时进行回滚,默认情况下,Spring只会对RuntimeExceptionError进行回滚。
  5. 事务超时:可以设置事务的超时时间,超时后自动回滚。

使用方式

添加依赖

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>

@Transactional可以用在类或方法上:

  • 类级别:在类上使用时,所有方法都会参与事务。
  • 方法级别:在方法上使用时,只有该方法会参与事务。
示例代码:
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;

@Service
public class AccountService {

    @Transactional
    public void transferMoney(Account fromAccount, Account toAccount, double amount) {
        // 执行转账操作
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
    }
}
  • ⽅法/类被 @Transactional 注解修饰时, 在⽬标⽅法执⾏开始之前, 会⾃动开启事务, ⽅法执⾏结束之后, ⾃动提交事务.
  • 如果在⽅法执⾏过程中, 出现异常, 且异常未被捕获, 就进⾏事务回滚操作.
  • 如果异常被程序捕获, ⽅法就被认为是成功执⾏, 依然会提交事务.

手动回滚事务

TransactionAspectSupport 是 Spring AOP 事务支持的一个类,它提供了对当前事务状态的访问。通过 currentTransactionStatus() 获取当前事务的状态,并调用 setRollbackOnly() 方法标记事务为回滚状态,从而在事务提交时强制回滚。

使用场景

通常在业务逻辑中,如果发生某些特定的异常或需要根据业务条件回滚事务时,可以手动调用 setRollbackOnly(),这样Spring会在事务提交时回滚事务。

示例代码

假设你有一个业务服务,想根据某些条件决定是否回滚事务:

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

@Service
public class AccountService {

    @Transactional
    public void transferMoney(Account fromAccount, Account toAccount, double amount) {
        // 执行转账操作
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);

        // 根据业务逻辑判断是否回滚事务
        if (amount < 0) {
            // 如果金额小于0,手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }
}

解释

  1. @Transactional 注解标注了整个方法,表示方法中的操作都在一个事务中执行。
  2. 在方法内部,如果发现金额小于0,就调用 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() 来标记事务为回滚状态。
  3. 当事务提交时,Spring会发现事务标记为回滚状态,并会自动回滚事务。

在Spring的@Transactional注解中,isolation属性用于定义事务的隔离级别。事务的隔离级别决定了一个事务内的操作对其他并发事务的可见性,以及其他事务的操作对当前事务的影响。通过设置适当的隔离级别,可以有效地控制并发事务对数据的一致性和完整性所带来的影响。

事务隔离级别

数据库的事务隔离级别通常定义了一个事务内操作的数据在提交之前是否对其他事务可见。事务隔离级别越高,系统的并发性可能会越低,但数据一致性和安全性会更高。常见的事务隔离级别有四种,它们的定义如下:

  1. READ_UNCOMMITTED(读取未提交):
    • 允许事务读取其他事务未提交的数据。
    • 可能会导致脏读(Dirty Read),即一个事务读取到另一个事务尚未提交的脏数据。
    • 最低的隔离级别,对并发性能有较少影响,但会导致数据不一致。
  2. READ_COMMITTED(读取已提交):
    • 只允许读取其他事务已提交的数据。
    • 可以避免脏读,但是可能会出现不可重复读(Non-repeatable Read),即在同一个事务内,如果读取相同数据,可能会得到不同的结果,因为其他事务可能已修改了数据。
    • 是大多数数据库的默认隔离级别。
  3. REPEATABLE_READ(可重复读取):
    • 保证事务内读取的数据在事务执行期间不会被其他事务修改。
    • 避免了脏读和不可重复读,但可能会导致幻读(Phantom Read),即事务内的查询结果在执行过程中可能会因为其他事务的插入操作而发生变化。
  4. SERIALIZABLE(串行化):
    • 是最高的隔离级别,所有事务按顺序执行,模拟为串行执行。
    • 事务之间完全隔离,可以避免脏读、不可重复读和幻读。
    • 由于严格的隔离性,会显著降低并发性,可能导致性能瓶颈。

Spring 中的 @Transactional isolation 属性

在Spring的@Transactional注解中,isolation属性允许你指定事务的隔离级别。它的默认值通常是Isolation.DEFAULT,表示使用底层数据库的默认隔离级别。如果你希望显式指定某个隔离级别,可以使用以下选项:

import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.annotation.Isolation;

@Transactional(isolation = Isolation.READ_COMMITTED)
public void someMethod() {
    // 业务逻辑
}

Spring 提供的隔离级别选项

  • Isolation.DEFAULT:使用底层数据库的默认隔离级别,通常是READ_COMMITTED
  • Isolation.READ_UNCOMMITTED:读取未提交的事务数据,可能会导致脏读。
  • Isolation.READ_COMMITTED:读取已提交的数据,可以防止脏读。
  • Isolation.REPEATABLE_READ:可重复读取,防止脏读和不可重复读。
  • Isolation.SERIALIZABLE:串行化,事务完全隔离,防止脏读、不可重复读和幻读。

示例

假设你有一个银行转账业务,需要确保转账过程中的一致性。你可以使用@Transactional注解来定义事务的隔离级别,确保在高并发环境下的事务隔离性。

import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

public class BankService {

    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void transferMoney(Account fromAccount, Account toAccount, double amount) {
        // 从fromAccount账户中扣款
        fromAccount.withdraw(amount);

        // 向toAccount账户中存款
        toAccount.deposit(amount);
    }
}

在上述代码中,@Transactional注解使用了READ_COMMITTED隔离级别,确保在转账过程中,fromAccounttoAccount的余额在事务提交之前是不可见的。

隔离级别的影响

  • 性能:较低的隔离级别(如READ_UNCOMMITTED)会提高并发性,但可能会引发脏读、不可重复读等问题。而较高的隔离级别(如SERIALIZABLE)则会降低并发性,但保证数据的一致性。
  • 一致性:较高的隔离级别可以保证更高的数据一致性,避免脏读、不可重复读和幻读。但代价是性能会受影响。

事务传播机制

在Spring的@Transactional注解中,propagation属性用于定义事务的传播行为,决定了一个事务方法在调用另一个事务方法时,事务如何传播。事务传播机制影响一个方法调用另一个方法时如何参与事务,决定了是加入现有事务、创建新事务还是不参与事务等行为。

常见的事务传播行为

Propagation.REQUIRED(默认传播行为):

  • 如果当前没有事务存在,则新建一个事务;如果当前存在事务,则加入到现有事务中。
  • 这是最常用的传播行为,也是默认行为。通常情况下,如果没有明确的需求,推荐使用此传播行为。

示例

@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
    // 如果没有事务,启动一个新的事务;如果已经有事务,加入当前事务
}

Propagation.SUPPORTS

  • 如果当前存在事务,则加入到事务中;如果没有事务,则以非事务的方式执行。
  • 当调用方法时,如果存在事务,方法会在事务内执行;如果没有事务,方法不会参与事务。

示例

@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
    // 如果没有事务,非事务执行;如果有事务,加入当前事务
}

Propagation.MANDATORY

  • 如果当前没有事务,则抛出异常;如果当前存在事务,则加入到现有事务中。
  • 强制要求方法必须在一个事务中运行。如果没有事务存在,Spring会抛出IllegalTransactionStateException异常。

示例

@Transactional(propagation = Propagation.MANDATORY)
public void methodC() {
    // 必须有一个已经存在的事务,如果没有事务,会抛出异常
}

Propagation.REQUIRES_NEW

  • 无论当前是否存在事务,都会创建一个新的事务;如果当前存在事务,则将当前事务挂起,直到新的事务提交或回滚后恢复。
  • 适用于需要独立运行的事务,确保方法执行时有一个新的事务与当前事务分离。

示例

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodD() {
    // 创建一个新的事务,挂起当前事务,提交后再恢复当前事务
}

Propagation.NOT_SUPPORTED

  • 如果当前存在事务,则挂起当前事务,并以非事务的方式执行方法;如果没有事务,方法则以非事务的方式执行。
  • 适用于需要禁用事务的场景,无论当前是否有事务,都不使用事务。

示例

@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodE() {
    // 不使用事务,无论当前是否有事务
}

Propagation.NEVER

  • 如果当前存在事务,则抛出异常;如果没有事务,则以非事务的方式执行。
  • MANDATORY类似,但NEVER明确要求方法不在事务中执行。如果当前有事务,Spring会抛出IllegalTransactionStateException异常。

示例

@Transactional(propagation = Propagation.NEVER)
public void methodF() {
    // 如果当前有事务,则抛出异常;没有事务时,以非事务方式执行
}

Propagation.NESTED

  • 如果当前存在事务,则在当前事务内创建一个嵌套事务;如果没有事务,则与REQUIRED类似,创建一个新的事务。
  • 嵌套事务是通过保存点实现的,如果外部事务回滚,嵌套事务也会回滚。否则,嵌套事务可以独立提交。

示例

@Transactional(propagation = Propagation.NESTED)
public void methodG() {
    // 如果存在事务,创建一个嵌套事务;如果没有事务,创建一个新的事务
}

传播行为总结

传播行为描述
REQUIRED默认行为,存在事务时加入事务;不存在时创建新事务。
SUPPORTS如果存在事务,则加入事务;如果不存在事务,则不使用事务。
MANDATORY必须有事务,若无事务则抛出异常。
REQUIRES_NEW创建一个新事务,挂起当前事务。
NOT_SUPPORTED不使用事务,挂起当前事务(如果存在)。
NEVER不在事务中执行,若存在事务则抛出异常。
NESTED如果存在事务,则创建一个嵌套事务;否则创建一个新事务。

示例:事务传播行为的使用

假设你有两个方法methodAmethodB,你希望methodA执行时可以自动加入现有事务,而methodB则需要每次都新建事务,即使methodA已经有事务存在。

import org.springframework.transaction.annotation.Transactional;

public class TransactionService {

    @Transactional(propagation = Propagation.REQUIRED)
    public void methodA() {
        // 这个方法如果没有事务,会创建新事务,如果有事务,会加入现有事务
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void methodB() {
        // 这个方法总是会创建新的事务,挂起当前事务
    }
}

在这个例子中:

  • 当你调用methodA时,它会尝试使用已有的事务,或者如果没有事务会启动新的事务。
  • 调用methodB时,无论methodA是否在事务中执行,methodB都会启动一个新的事务,并挂起methodA的事务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文详解Filter类源码和应用

背景 在日常开发中&#xff0c;经常会有需要统一对请求做一些处理&#xff0c;常见的比如记录日志、权限安全控制、响应处理等。此时&#xff0c;ServletApi中的Filter类&#xff0c;就可以很方便的实现上述效果。 Filter类 是一个接口&#xff0c;属于 Java Servlet API 的一部…

开发环境搭建-1:配置 WSL (类 centos 的 oracle linux 官方镜像)

一些 Linux 基本概念 个人理解&#xff0c;并且为了便于理解&#xff0c;可能会存在一些问题&#xff0c;如果有根本上的错误希望大家及时指出 发行版 WSL 的系统是基于特定发行版的特定版本的 Linux 发行版 有固定组织维护的、开箱就能用的 Linux 发行版由固定的团队、社区…

llama-2-7b权重文件转hf格式及模型使用

目录 1. obtain llama weights 2. convert llama weights files into hf format 3. use llama2 to generate text 1. obtain llama weights &#xff08;1&#xff09;登录huggingface官网&#xff0c;搜索llama-2-7b &#xff08;2&#xff09;填写申请表单&#xff0c;VP…

ElasticSearch(十一)— Elasticsearch中的SQL语句

一、总概 Elasticsearch 在 Basic 授权中支持以 SQL 语句的形式检索文档&#xff0c;SQL 语句在执行时会被翻译为 DSL 执行。从语法的角度来看&#xff0c;Elastisearch 中的 SQL 语句与RDBMS 中的 SQL 语句基本一致&#xff0c; 所以对于有数据库编程基础的人来说大大降低了使…

吴恩达深度学习——如何实现神经网络

来自吴恩达深度学习&#xff0c;仅为本人学习所用。 文章目录 神经网络的表示计算神经网络的输出激活函数tanh选择激活函数为什么需要非激活函数双层神经网络的梯度下降法 随机初始化 神经网络的表示 对于简单的Logistic回归&#xff0c;使用如下的计算图。 如果是多个神经元…

爬取NBA球员信息并可视化小白入门

网址:虎扑体育-NBA球员得分数据排行 第1页 步骤: 分析页面 确定URL地址模拟浏览器向服务器发送请求数据解析 提取想要的数据保存数据 爬虫所需要的模块 requests(发送HTTP请求)parsel(解析HTML内容)pandas(数据保存模块) 第一步分析页面 --确定是静态页面还是动态页面 右击点…

C语言初阶牛客网刷题——JZ17 打印从1到最大的n位数【难度:入门】

1.题目描述 牛客网OJ题链接 题目描述&#xff1a; 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直到最大的 3 位数 999。 用返回一个整数列表来代替打印n 为正整数&#xff0c;0 < n < 5 示例1 输入&…

寒假刷题记录

4968. 互质数的个数 - AcWing题库 涉及&#xff1a;快速幂&#xff0c;欧拉函数&#xff0c;分解质因数 #include <bits/stdc.h> #define fi first #define se second #define endl \n #define pb push_backusing namespace std; using LL long long;const int mod 9…

OSI5GWIFI自组网协议层次对比

目录 5G网络5G与其他协议栈各层映射 5G网络 物理层 (PHY) 是 5G 基站协议架构的最底层&#xff0c;负责将数字数据转换为适合无线传输的信号&#xff0c;并将接收到的无线信号转换为数字数据。实现数据的编码、调制、多天线处理、资源映射等操作。涉及使用新的频段&#xff08…

Java高频面试之SE-16

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本牛马baby今天又来了&#xff01;哈哈哈哈哈嗝&#x1f436; Java中异常的处理方式有哪些&#xff1f; 在 Java 中&#xff0c;异常的处理方式主要有以下几种&#xff1a; 1. 使用 try-catch 语句 …

HTML中的`<!DOCTYPE html>`是什么意思?

诸神缄默不语-个人CSDN博文目录 在学习HTML时&#xff0c;我们经常会看到HTML文档的开头出现<!DOCTYPE html>&#xff0c;它是HTML文件的第一行。很多初学者可能会疑惑&#xff0c;为什么需要这行代码&#xff1f;它到底有什么作用呢&#xff1f;在这篇文章中&#xff0…

Games104——游戏中地形大气和云的渲染

原文链接 原文链接 这里写目录标题 地形的几何Heightfield高程图网格自适应细分三角形的剖分二叉树T-Junctions四叉树TIN&#xff08;Triangulated Irregular Network&#xff09;不规则三角形网格 GPU Drived Tessellator(Hardware Tessellation)Mesh ShaderNon-HeightField…

Springboot自动配置的原理

先拿redis来举个例子 第一步导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 第二步配置 spring: redis: database:host:127.0.0.1 port…

【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题

本篇博客给大家带来的是01背包问题之动态规划解法技巧. &#x1f40e;文章专栏: 动态规划 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; 要开心要快乐顺便…

记一次虚机上传过慢问题排查

最近线上虚机有个特殊的用户反馈&#xff0c;用户反馈虚机从A服务器下载文件特别慢&#xff0c;于是scp A服务器数据到本地client&#xff0c;发现 只有几十K的流量。 当时第一反应怀疑是虚机负载压力比较大&#xff0c;但是查看虚机IO以及负载都很低。。。。 然后tcpdump抓包发…

web服务器 网站部署的架构

WEB服务器工作原理 Web web是WWW(World Wide Web)的简称&#xff0c;基本原理是&#xff1a;请求(客户端)与响应(服务器端)原理&#xff0c;由遍布在互联网中的Web服务器和安装了Web浏览器的计算机组成 客户端发出请求的方式&#xff1a;地址栏请求、超链接请求、表单请求 …

数据结构——实验七·排序

嗨~~欢迎来到Tubishu的博客&#x1f338;如果你也是一名在校大学生&#xff0c;正在寻找各种编程资源&#xff0c;那么你就来对地方啦&#x1f31f; Tubishu是一名计算机本科生&#xff0c;会不定期整理和分享学习中的优质资源&#xff0c;希望能为你的编程之路添砖加瓦⭐&…

Windows系统提示RunDLL PcaWallpaperAppDetect错误修复方法

最近&#xff0c;Win11 24H2预览版和Win10 LTSC 2025功能更新偶尔会触发RunDLL错误弹窗 具体表现为 //英文提示 Error in C:\WINDOWS\system32\PcaSvc.dll Missing entry: PcaWallpaperAppDetect//中文提示 C:\WINDOWS\system32\PcaSvc.dll出错 丢失条目:PcaWallpaperAppDe…

计算机组成原理——数据表示(二)

当生活的压力和困惑缠绕在身边&#xff0c;我们往往需要振奋精神&#xff0c;勇往直前。无论在何种困境中&#xff0c;我们都要保持积极的态度和坚定的信念。将悲观的情绪抛之脑后&#xff0c;展现出坚强的意志力和无尽的活力。振奋精神意味着我们要战胜自己内心的负面情绪&…

人源化抗体的改造方式及其优势【卡梅德生物】

随着生物制药行业的迅速发展&#xff0c;抗体药物已经成为治疗多种疾病&#xff08;尤其是癌症、免疫性疾病等&#xff09;的重要手段。抗体人源化改造技术作为抗体药物研发的关键技术之一&#xff0c;在提高药物疗效和降低免疫原性方面发挥了至关重要的作用。 1. 人源化抗体的…