Spring事务详解——面试必看!

Spring事务

什么是事务

事务是逻辑上的一组操作要么全都执行,要么全都不执行

同时,事务能否生效数据库引擎是否支持事务是关键。比如常用的 MySQL 数据库默认使用支持事务的 innodb引擎。但是,如果把数据库引擎变为 myisam,那么程序也就不再支持事务了!

MySql怎么保证原子性

首先,要想保证的原子性,就需要在出现异常时,对已经执行的操作进行回滚(rollback),在mysql中,恢复机制是通过回滚日志(undo log)实现的,所有事物进行的修改都会先记录到这个日志中,然后再执行。若执行遇到异常,直接利用 回滚日志 中的信息将数据回滚到修改之前的样子即可。并且,回滚日志会先于数据持久化到磁盘上

Spring支持两种方式的事务管理

编程式事务管理

通过 TransactionTemplate或者TransactionManager手动管理事务

声明式事务管理

推荐使用(代码侵入性最小),实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)。

例子如下:

@Transactional(propagation = Propagation.REQUIRED)
public void aMethod {
  //do something
  B b = new B();
  C c = new C();
  b.bMethod();
  c.cMethod();
}

Spring事务管理接口介绍

Spring 框架中,事务管理相关最重要的 3 个接口如下:

  • PlatformTransactionManager:平台事务管理器,Spring事务策略的核心
  • TranscationDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)
  • TranscationState:事务运行状态

PlatformTranscationManager会根据TranscationDefinition的定义比如事务隔离级别、超时时间、传播行为等来进行事务管理,而 TransactionStatus 接口则提供了一些方法来获取事务相应的状态比如是否新事务、是否可以回滚等等。

PlatformTranscationManager事务管理接口

Spring并不直接管理事务,而是提供了多种事务管理器。Spring事务管理器的接口是:PlatformTranscationManager

PlatformTranscationManager中定义了三个方法:

package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface PlatformTransactionManager {
    //获得事务
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    //提交事务
    void commit(TransactionStatus var1) throws TransactionException;
    //回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}
TranscationDefinition:事务属性

事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。

什么是事务属性呢? 事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。

事务属性包含了 5 个方面:

  • 隔离级别
  • 传播行为
  • 回滚规则
  • 是否只读
  • 事务超时
TranscationState事务状态

TransactionStatus接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。

PlatformTransactionManager.getTransaction(…)方法返回一个 TransactionStatus 对象。

接口内容如下:

public interface TransactionStatus{
    boolean isNewTransaction(); // 是否是新的事务
    boolean hasSavepoint(); // 是否有恢复点
    void setRollbackOnly();  // 设置为只回滚
    boolean isRollbackOnly(); // 是否为只回滚
    boolean isCompleted; // 是否已完成
}

事务属性详解

事务传播行为

事务传播行为是为了解决业务层方法之间互相调用的事务问题。

当一个事务方法被另一个事务方法调用时,必须规定事务应当如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。

TransactionDefinition定义中包括了如下几个表示传播行为的常量:

public interface TransactionDefinition {
    int PROPAGATION_REQUIRED = 0;   
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
    ......
}

不过,为了方便使用,Spring 相应地定义了一个枚举类:Propagation

package org.springframework.transaction.annotation;

import org.springframework.transaction.TransactionDefinition;

public enum Propagation {
	//默认的事务传播行为
    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

    NEVER(TransactionDefinition.PROPAGATION_NEVER),

    NESTED(TransactionDefinition.PROPAGATION_NESTED);

    private final int value;

    Propagation(int value) {
        this.value = value;
    }

    public int value() {
        return this.value;
    }

}
正确的事务传播行为
  • TransactionDefinition.PROPAGATION_REQUIRED

    使用最多的一种传播行为,通常@Transcational默认的就是该行为,意思是如果当前存在事务,就加入该事务;若没有,则创建一个新的事务。也就是:

    • 如果外部方法没有开启事务,则PROPAGATION_REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰
    • 如果外部方法开启事务并且被Propagation.REQUIRED的话,所有Propagation.REQUIRED修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务均回滚
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW

    创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。

  • TransactionDefinition.PROPAGATION_NESTED

    如果当前存在事务,就在嵌套事务内执行;如果当前没有事务,就执行与TransactionDefinition.PROPAGATION_REQUIRED类似的操作。也就是说:

    • 在外部方法开启事务的情况下,在内部开启一个新的事务,作为嵌套事务存在
    • 如果外部方法无事务,则单独开启一个事务,与 PROPAGATION_REQUIRED 类似。
  • TransactionDefinition.PROPAGATION_MANDATORY

    如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

若是错误的配置以下 3 种事务传播行为,事务将不会发生回滚

TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

事务隔离级别
  • TransactionDefinition.ISOLATION_DEFAULT :使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED :最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
事务超时属性

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int的值来表示超时时间,其单位是秒,默认值为-1,这表示事务的超时时间取决于底层事务系统或者没有超时时间。

事务只读属性
package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface TransactionDefinition {
    ......
    // 返回是否为只读事务,默认值为 false
    boolean isReadOnly();

}

对于只有读取数据查询的事务,可以指定事务类型为 readonly,即只读事务。只读事务不涉及数据的修改,数据库会提供一些优化手段,适合用在有多条数据库查询操作的方法中。

  • 如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持 SQL 执行期间的读一致性;
  • 如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询 SQL 必须保证整体的读一致性,否则,在前条 SQL 查询之后,后条 SQL 查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持
事务回滚规则

这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常(RuntimeException 的子类)时才会回滚,Error 也会导致事务回滚,但是,在遇到检查型(Checked)异常时不会回滚

如果你想要回滚你定义的特定的异常类型的话,可以这样:

@Transactional(rollbackFor= MyException.class)

@Transcational注解的使用

@Transcational注解的使用范围
  • 方法:推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效。
  • :如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效。
  • 接口:不推荐在接口上使用。
@Transactional 的常用配置参数总结(只列出了 5 个平时比较常用的):
属性名说明
propagation事务的传播行为,默认值为 REQUIRED
isolation事务的隔离级别,默认值采用 DEFAULT
timeout事务的超时时间,默认值为-1(不会超时)。如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly指定事务是否为只读事务,默认值为 false。
rollbackFor用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。
@Transcational注解的原理

@Transactional 的工作机制是基于 AOP 实现的,AOP 又是使用动态代理实现的。如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理,如果目标对象没有实现了接口,会使用 CGLIB 动态代理。(createAopProxy() 方法 决定了是使用 JDK 还是 Cglib 来做动态代理)

如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候为其创建一个代理类,在调用@Transactional 注解的 public 方法的时候,实际调用的是,TransactionInterceptor 类中的 invoke()方法。这个方法的作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务。

TransactionInterceptor 类中的 invoke()方法内部实际调用的是 TransactionAspectSupport 类的 invokeWithinTransaction()方法。

SpringAOP的自调用问题

当一个方法被标记了@Transactional 注解的时候,Spring 事务管理器只会在被其他类方法调用的时候生效,而不会在一个类中方法调用生效

这是因为 Spring AOP 工作原理决定的。因为 Spring AOP 使用动态代理来实现事务的管理,它会在运行的时候为带有 @Transactional 注解的方法生成代理对象,并在方法调用的前后应用事物逻辑。如果该方法被其他类调用我们的代理对象就会拦截方法调用并处理事务。但是在一个类中的其他方法内部调用的时候,我们代理对象就无法拦截到这个内部调用,因此事务也就失效了。

解决办法就是避免同一类中自调用或者使用 AspectJ 取代 Spring AOP 代理

@Transcational使用注意事项总结
  • @Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;
  • 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效(SpringAOP的自调用问题);
  • 正确的设置 @TransactionalrollbackForpropagation 属性,否则事务可能会回滚失败;
  • @Transactional 注解的方法所在的类必须被 Spring 管理,否则不生效;
  • 底层使用的数据库必须支持事务机制,否则不生效;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3移动端可同时上传照片和视频的组件

uni-app中的uni-file-picker可单独上传照片或视频,但不支持同时上传照片和视频。本篇博客使用image标签和video标签实现移动端(H5app小程序)中照片和视频的同时上传。 本篇博客采用的是照片和视频的单独上传,但可同时展示&#xf…

Qt(简介)

1. Qt简介 Qt是一个基于C的图形用户界面(GUI)框架,可以开发可视化人机交互程序,但是这并不是Qt的全部。Qt除了可以绘制漂亮的界面外,还包含很多其他的功能:多线程、数据库、图像处理、音视频处理、网络通信…

后台管理员登录实现--系统篇

我的小系统后台原来就有一个上传图片的功能还夹带个删除图片的功能,还嵌到了一个菜单里面。之前效果如下 那么现在为了加大安全力度,想增加一个登录页面。通过登录再到这个页面。看着貌似很简单,但是听我细细说来,要新增些什么东西…

MySQL-视图 (ಥ_ಥ)

文本目录: ❄️一、什么是视图: ❄️二、创建视图: ❄️三、使用视图: ❄️四、修改数据: 1、注意事项: ❄️五、删除视图: ❄️六、视图的优点: ❄️总结: 对于这…

HT7179 26.8V,15A高效升压转换器

1、特征 输入电压范围:2.7V-25V 输出电压范围:最高26.8V 固定开关频率:350kHz 可编程峰值电流:最高15A 高转换效率1 95% (PVIN 12V, VOUT25V, IOUT 2A) 94%(PVIN 12V, VOUT25V, IOUT 4.5A) 93%(PVIN 7.2V, VOUT12V, IOUT 1.5A) 90% (PVIN 7.2V, VOUT12V, IOUT 5A) 96%(PVIN…

Perl打印9x9乘法口诀

本章教程主要介绍如何用Perl打印9x9乘法口诀。 一、程序代码 1、写法① use strict; # 启用严格模式,帮助捕捉变量声明等错误 use warnings; # 启用警告,帮助发现潜在问题# 遍历 1 到 9 的数字 for my $i (1..9) {# 对于每个 $i,遍历 1…

MoCoOp: Mixture of Prompt Learning for Vision Language Models

文章汇总 当前的问题 1)数据集风格变化。 如图1所示,对于一个数据集,单个软提示可能不足以捕获数据中呈现的各种样式。同一数据集中的不同实例可能与不同的提示符兼容。因此,更**自然的做法是使用多个提示来充分表示这些变化**。 2)过拟合…

V4L2驱动框架

文章目录 一、V4L2简介二、v4l2驱动关键组件(一)video_device结构体v4l2操作方法结构体v4l2的ioctl操作方法结构体 (二)v4l2_device结构体 一、V4L2简介 V4L2,即Video for Linux two,是Linux内核中用于视频…

qt项目使用其他项目的ui之单继承之成员变量

第一步添加.ui文件 第二步&#xff0c;点击编译(原理&#xff1a;qt的uic会将.ui界面编译成c文件) 第三步&#xff1a;在编译后的目录下找到#include “ui_pagewidget.h” 第四步&#xff1a; #ifndef USA_H #define USA_H#include <QWidget>#include "ui_pagew…

设计模式概览

设计模式是一种解决常见编程问题的经验总结&#xff0c;提供了代码的可重用性、可扩展性和可维护性。常见的设计模式有23个&#xff0c;主要分为三大类&#xff1a;创建型模式、结构型模式和行为型模式。下面是这三类设计模式的详细分类和讲解&#xff1a; 一、创建型模式 创建…

记一个src中危-图像大小与请求参数可修改

记一个src中危-图像大小与请求参数可修改 漏洞描述 服务器生成了一个具有客户端指定尺寸的图像&#xff0c;如果未实施任何限制&#xff0c;则可能导致拒绝服务攻击。 漏洞危害 攻击者不需要在此类攻击中投入资源&#xff0c;但服务器可能会分配所需的像素缓冲区&#xff0…

rk3588_DRM_显示

DRM简介&#xff08;Direct Rendering Manager&#xff09; hdmi 查看hdmir接口状态 cat /sys/class/drm/card0-HDMI-A-2/statusconnected 参考文章 rk3588_dp调试_rk3588 dp接口适配-CSDN博客

十六、【智能体】如何高效利用智能体知识库:打造智能助理的核心支撑

“知识库” 节点可以理解为一个集中存储和管理知识的地方。 就像一个装满各种工具和资源的工具箱&#xff0c;它包含了大量的信息、数据、文档、经验总结等各种知识内容。 为我们提供了一个便捷的途径来获取所需的知识&#xff0c;以解决问题、做出决策或者进行学习和研究。 …

Windows无法打开组策略 | Windows家庭版如何添加和打开组策略

什么是组策略&#xff08;Group Policy&#xff09;&#xff1f; 组策略 是微软Windows操作系统中的一个重要功能&#xff0c;它允许系统管理员通过统一的界面集中配置计算机和用户设置。 组策略设置是通过编辑“组策略对象”&#xff08;GPOs&#xff09;来实现的&#xff0c;…

攻坚金融关键业务系统,OceanBase亮相2024金融科技大会

10月15-16日&#xff0c;第六届中新数字金融应用博览会与2024金融科技大会&#xff08;简称“金博会”&#xff09;在苏州工业园区联合举办。此次大会融合了国家级重要金融科技资源——“中国金融科技大会”&#xff0c;围绕“赋能金融高质量发展&#xff0c;金融科技创新前行”…

Python 学习笔记(十二)—— 网络编程

目录 一、网络编程的基本概念 1.1 IP地址 1.1.1 IP的版本 1.1.2 IP的分类 1.1.2.1 公有地址 1.1.2.2 私有地址 1.1.3 IP地址的范围 1.1.4 回环测试 1.2 常见的网络设备 1.3 端口 1.3.1 端口分配 二、网络通信协议 2.1 常用网络协议 2.2 OSI网络协议七层模型 2.3…

几张图就让你掌握InnoDB 存储引擎底层逻辑架构

前言 &#x1f680; 博主介绍&#xff1a;大家好&#xff0c;我是无休居士&#xff01;一枚任职于一线Top3互联网大厂的Java开发工程师&#xff01; &#x1f680; &#x1f4a1; 无论你是刚刚踏入编程世界的新人&#xff0c;还是希望进一步提升自己的资深开发者&#xff0c;…

10.24.2024刷华为OD C题型(四) -- 对象list按照多个属性排序

文章目录 最长连续子序列AI面板识别语法知识记录 最长连续子序列 https://www.nowcoder.com/discuss/592408743019589632 if __name__ "__main__":# 获取用户输入# numbers int(input().split(,))# str_arr input().split(,)arr [int(num) for num in input(…

【安装教程】使用WSL工具,在Windows11系统上安装Linux模拟环境(逐步教程)

目录 一、为什么要学习Linux系统 二、Linux模拟环境&#xff08;WSL&#xff09; WSL的官方文档 1、下载WSL 2、安装Ubuntu 结语 提示&#xff1a;WSL下的Linux模拟环境是纯命令行操作的。如果想要使用桌面系统&#xff0c;则应该考虑其他的虚拟机&#xff0c;如VMware。我…

从校园到职场:Java实习生面试常见问题

Java实习生面试通常会涵盖多个方面的知识&#xff0c;包括基础知识、项目经验、解决问题的能力以及面试技巧。以下是一些常见的Java实习生面试题及其回答技巧&#xff1a; Java基础知识 问题&#xff1a;Java有那些基本数据类型&#xff0c;String是不是基本数据类型&#xff…