# Spring 事务失效场景

news/2023/12/5 1:30:40

Spring 事务失效场景

文章目录

  • Spring 事务失效场景
    • 前言
    • 事务不生效
      • 未开启事务
      • 事务方法未被Spring管理
      • 访问权限问题
        • 基于接口的代理
          • 源码解读
        • CGLIB代理
      • 方法用final修饰
      • 同一类中的方法调用
      • 多线程调用
      • 不支持事务
    • 事务不回滚
      • 设置错误的事务传播机制
      • 捕获了异常
      • 手动抛了别的异常
      • 自定义了回滚异常
      • 事务被手动提交
    • 其它
      • 大事务问题
        • 缩小事务范围
        • 手动提交事务
        • 异步处理
      • 事务的性能和并发性

前言

# Spring事务详解

  1. Spring事务是用于解决数据库操作中的一致性和隔离性问题的机制。数据库事务是一组操作,要么全部成功执行,要么全部回滚,以确保数据的完整性和一致性。
  2. Spring事务管理的主要目的是确保在多个数据库操作中,要么所有操作都成功提交,要么所有操作都回滚,从而保持数据的一致性。它提供了以下几个方面的解决方案:
  • 原子性(Atomicity):事务要么全部成功执行,要么全部回滚,确保数据库操作的原子性。

  • 一致性(Consistency):事务在执行前后,数据库的状态应保持一致。如果事务执行失败,数据库应该回滚到事务开始之前的状态。

  • 隔离性(Isolation):事务应该在相互之间隔离,以避免并发操作引起的问题。它确保了在并发环境下,每个事务都能够独立地执行,并且不会相互干扰。

  • 持久性(Durability):一旦事务提交,其结果应该持久保存在数据库中,即使发生系统故障或重启。

  1. Spring事务管理通过使用注解或编程方式来定义事务边界,它可以应用于各种数据访问技术(如JDBCHibernateJPA等)。它还提供了不同的传播行为和隔离级别,以满足不同的业务需求。
  2. 通过使用Spring事务,开发人员可以简化数据库操作的管理,并确保数据的一致性和可靠性,从而提高应用程序的可靠性和性能。

事务不生效

未开启事务

  • 如果使用的是springboot项目,springboot通过DataSourceTransactionManagerAutoConfiguration类,默认开启了事务。只需要配置spring.datasource相关参数即可。
    在这里插入图片描述
  • 如果使用的是传统的spring项目,则需要在applicationContext.xml文件中,手动配置事务相关参数。如果忘了配置,事务肯定是不会生效的。

事务方法未被Spring管理

  • 未将类标记为 Spring 管理的组件:确保类被标记为 @Service@Component 或其他适当的注解,以便 Spring 能够扫描并管理该类。
  • 未使用 @Transactional 注解标记事务方法:确保需要进行事务管理的方法被标记为 @Transactional 注解,以便 Spring 能够识别并应用事务管理。

访问权限问题

基于接口的代理
  • 当使用基于代理的事务管理时,Spring会在运行时生成一个代理对象来管理事务。这个代理对象会拦截被注解的方法,并在方法执行前后进行事务的开启、提交或回滚等操作。
  • 默认情况下,Spring的事务代理是基于接口实现的,因此只有public方法才能被代理。如果事务方法是privateprotected或默认访问级别的,Spring无法生成代理对象,从而导致事务不生效。
/*** 不生效*/
@Transactional
private void ransactionOne() {User user = new User();user.setUsername("张三");userMapper.insertUser(user);methodOne();int a = 3 / 0;logger.info(String.valueOf(a));
}
源码解读
  • 判断是否是public
    在这里插入图片描述

  • 有事务的类
    在这里插入图片描述

CGLIB代理
  • 如果使用基于类的代理,即使用CGLIB代理,Spring可以代理非public方法。可以通过配置 proxy-target-class 属性为true来启用基于类的代理。
  • 如果使用的是基于类的代理,事务方法可以是非public的,但需要启用基于类的代理。
  • SpringBoot 事务示例:通过在 @EnableTransactionManagement 注解上设置 proxyTargetClass 属性为true来启用基于类的代理。
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class AppConfig {// 配置其他的Bean和组件
}
  • 使用基于类的代理时,非public方法也可以被代理。但需要注意,启用基于类的代理可能会带来一些性能开销,因此只有在确实需要代理非public方法时才应使用。
  • 确保在配置类上添加了 @EnableTransactionManagement 注解,并根据需要设置 proxyTargetClass 属性,就可以在Spring Boot中使用基于类的代理来进行事务管理了。
  • Spring使用CGLIB库的Enhancer类来生成代理对象,生成的代理对象中包含EnhancerBySpringCGLIB作为标识符
    在这里插入图片描述

方法用final修饰

  • Spring 中,事务是通过动态代理来实现的。当一个类被代理时,Spring 会创建一个代理对象来包装原始对象,从而在方法调用前后添加事务处理逻辑。然而,对于 final 方法,由于无法重写,因此无法创建代理对象,事务管理器也就无法对其进行事务处理。
@Service
public class UserService {@Transactionalpublic final void add(UserModel userModel){saveData(userModel);updateData(userModel);}
}

同一类中的方法调用

  • this是被真实对象,所以会直接走methodTwo的业务逻辑,而不会走切面逻辑,所以事务失败。
/*** 同一个类中的方法调用*/
@Override
public void transactionSix() {User user = new User();user.setUsername("张三");userMapper.insertUser(user);// 没有事务的方法调用有事务的方式,相当于使用 this 调用不会走 AOP 的逻辑methodTwo();
}@Transactional(rollbackFor = Throwable.class)
public void methodTwo() {User user = new User();user.setUsername("李四");userMapper.insertUser(user);int a = 5 / 0;logger.info(String.valueOf(a));
}
  • 解决方法可以是在方法上添加@Transactional注解
  • @EnableAspectJAutoProxy(exposeProxy = true)在启动类中添加,会由Cglib代理实现。
  • 如果只想让methodTwo的事务生效,可以把methodTwo写到一个新的service,用service调用
/*** 同一个类中的方法调用,调用 service 的方法,insetUser 方法事务可以生效*/
@Override
public void transactionSeven(){User user = new User();user.setUsername("张三");userMapper.insertUser(user);transactionHelpService.insetUser();
}@Transactional(rollbackFor = Throwable.class)
@Override
public void insetUser() {User user = new User();user.setUsername("李四");userMapper.insertUser(user);int a = 5 / 0;logger.info(String.valueOf(a));
}

多线程调用

  • 同一个事务,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。如果在不同的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

不支持事务

  • 数据库本身无法支持事务的场景下,例如使用MysqlMyISAM引擎

  • MySQL5.5往后,默认采用InnoDB存储引擎,在这之前采用MyISAM存储引擎

  • InnoDBMySQL默认事务型引擎 ,它被设计用来处理大量的短期(short-lived)事务。可以确保事务的完整提交(Commit)和回滚(Rollback)

  • MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM 不支持事务、行级锁、外键 ,有一个毫无疑问的缺陷就是崩溃后无法安全恢复

事务不回滚

设置错误的事务传播机制

  • Propagation.NEVER:这种类型的传播特性不支持事务,如果有事务则会抛异常。
  • 目前只有这三种传播特性才会创建新事务:REQUIREDREQUIRES_NEWNESTED

捕获了异常

  • 在代码中手动try...catch了异常
@Transactional
@Override
public void testOne() {try {User user = new User();user.setUsername("张三");userMapper.insertUser(user);int a = 3 / 0;} catch (Exception e) {logger.error(e.getMessage(), e);}
}
  • Spring Boot中,事务是通过AOP(面向切面编程)机制实现的。当使用 @Transactional 注解标记一个方法时,Spring会在方法开始前创建一个事务,并在方法执行结束后根据方法的执行结果来决定是否提交或回滚事务。
  • 如果在方法执行期间发生异常,Spring会捕获该异常并将事务标记为“回滚”。这意味着在方法执行结束后,Spring会自动回滚该事务并撤销对数据库的任何更改。
  • 如果在方法中捕获了异常并处理了它,那么Spring就无法感知到该异常,并且不会将事务标记为“回滚”。这意味着在方法执行结束后,Spring会将事务提交,而不是回滚,这可能会导致不一致的数据状态。

手动抛了别的异常

  • spring事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),对于普通的Exception(非运行时异常),它不会回滚。
  • 如果在执行方法时抛出了 RuntimeException 类型的异常,Spring 会认为这个异常是不可恢复的,也就是说无法通过异常处理来修复。在这种情况下,Spring 会回滚事务,撤销之前的所有数据库操作,以保证数据的一致性。
  • 如果抛出的是非 RuntimeException 类型的异常,Spring 会认为这个异常是可以恢复的,意味着可以通过异常处理来修复。在这种情况下,Spring 不会回滚事务,而是允许应用程序继续执行。
  • 这个机制的主要目的是保护数据的一致性。在大多数情况下,如果发生了非 RuntimeException 类型的异常,应用程序可能会尝试通过其他方式来处理异常并继续执行。而如果发生了 RuntimeException 类型的异常,应用程序可能无法继续执行,因此需要回滚事务以撤销之前的数据库操作。
/*** 在代码中手动抛出别的异常 事务不回滚*/
@Override
public void testTwo() throws Exception {try {User user = new User();user.setUsername("张三");userMapper.insertUser(user);int a = 3 / 0;} catch (Exception e) {logger.error(e.getMessage(), e);throw new Exception("test");}
}

自定义了回滚异常

  • 在使用@Transactional注解声明事务时,有时我们想自定义回滚的异常,spring也是支持的。可以通过设置rollbackFor参数

  • rollbackFor 参数指定了回滚事务异常的类型,需要检查抛出的异常是否是指定的异常,如果不一致则回滚不了
    在这里插入图片描述

  • 开发规范中会提示需要指定rollbackFor参数,事务默认只会在捕获到未被处理的 RuntimeException 或 Error 时才会回滚。如果你的代码中捕获了异常并进行了处理,但没有再次抛出 RuntimeException 或 Error,事务将不会回滚。确保在捕获异常时,将异常重新抛出或手动触发回滚。

事务被手动提交

  • 如果在代码中手动调用了 commit() 方法来提交事务,而没有调用 rollback() 方法来回滚事务,事务将不会回滚。确保在需要回滚的情况下,正确地调用了回滚方法。

其它

大事务问题

缩小事务范围
  • 将大事务拆分为多个小事务,并使用嵌套事务来管理它们
手动提交事务
  • 如果需要更细粒度的控制,可以在代码中手动管理事务。使用 TransactionTemplate 类可以手动启动、提交或回滚事务
异步处理
  • 对于非关键的操作,你可以考虑使用异步处理来减少事务的时间。
  • 将一些长时间运行的操作放在异步任务中,这样可以减少事务的持有时间,从而减少事务的大小和影响范围。

事务的性能和并发性

  • 大事务可能会导致性能问题和并发性竞争。在设计事务时,要考虑事务的持有时间和锁竞争情况。尽量将事务范围缩小到最小,避免长时间持有事务锁,以提高性能和并发性。

http://www.ppmy.cn/news/1172294.html

相关文章

黑豹程序员-架构师学习路线图-百科:Java的第二春Spring框架

文章目录 1、 Spring的发展历史2、为什么Spring能霸屏?2.1、容器的设计2.2、通过四个策略2.3、三种方式 3、学习编程设计的典范 1、 Spring的发展历史 正当SUN公司的EJB在全球开始热炒时,正当程序员纷纷转型EJB开发时,正当程序员为跑通EJB程…

c语言一维数组和二维指针

c语言一维数组和二维指针&#xff1a;测试目的&#xff0c;了解二维指针赋值。 #include <stdio.h> //c语言一维数组和二维指针 int main(int argc,char *argv[]) { int MyArray[2]; int *p1; int **p2; //int **p2&p1;//在声明变量时&#xff0c;可以这么赋值 …

TCP--拥塞控制

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家来访。 TCP中另一个重要的点就是拥塞控制&#xff0c;TCP是无私的当它感受到网络拥堵了&#xff0c;就…

使用vscode搭建虚拟机

首先vscode插件安装 名称: Remote - SSH ID: ms-vscode-remote.remote-ssh 说明: Open any folder on a remote machine using SSH and take advantage of VS Codes full feature set. 版本: 0.51.0 VS Marketplace 链接: https://marketplace.visualstudio.com/items?it…

Go学习第六章——系统函数与错误处理

Go系统函数与错误处理 1 字符串相关系统函数2 时间和日期相关的函数2.1 Now函数2.2 日期的格式化 3 内置函数4 错误处理4.1 基本使用4.2 自定义错误 1 字符串相关系统函数 下面给出20个常见的函数&#xff0c;不需要导包&#xff0c;直接可以用 func main() {// 1.统计字符串…

Kafka 自动配置部署信息的脚本记录

自动配置 Kafka 整理服务器内容时&#xff0c;发现一个测试 Kafka 的的一个脚本&#xff0c;它可以自动部署 Kafka &#xff0c;指定三个参数&#xff0c;完成 Kafka 的配置过程。 basePath$1 brokerId$2 zookeeperConnect$3 localIpifconfig |grep inet| awk {print $2}| he…

Java Double和BigDecimal互转

一、Double转BigDecimal的方法 通过Double的valueOf方法转换 Double d 100.123456789;BigDecimal bd BigDecimal.valueOf(d);System.out.println("d " d);System.out.println("bd " bd); 二、BigDecimal转换为Double的方法 使用doubleValue()方法…

Linux防火墙Centos6的常用命令iptables

文章目录 一、iptables基础知识二、作者玩玩的配置文件三、iptables中常用的参数以及作用-j参数的动作类型 四、安装iptables五、iptables启动命令六、iptables命令结构命令例子默认执行方式执行iptables命令和写入配置文件两种方式的对比 相对常用的命令参考文档 一、iptables…

华为OD 矩阵最大值(100分)【java】B卷

华为OD统一考试A卷+B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入: 我用夸克网盘分享了「华为O…

2023年中国VR游戏市场发展分析:未来VR游戏市场规模增长潜力将逐步释放[图]

VR游戏它的原理就是利用电脑模拟产生一个三维空间的虚拟世界&#xff0c;提供使用者关于视觉、听觉、触觉等感官的模拟&#xff0c;让使用者感受到身临其境的体验&#xff0c;同时能够自由的与该空间内的事物进行互动。 VR游戏分类 资料来源&#xff1a;共研产业咨询&#xff…

VSCode 开发 Vue 语法提示

一. 打开应用商店&#xff0c;搜索 vetur &#xff0c;选择第一个&#xff0c;点击安装。 二. 安装完成后&#xff0c;还可以下载 Vue Language Features 解决代码警告的问题。 最后重启 VSCode 就可以使用啦。另外输入 按回车键还可以自动生成 vue 代码格式哦。 原创作者&…

vue重修之自定义项目、ESLint和代码规范修复

文章目录 VueCli 自定义创建项目ESlint代码规范及手动修复代码规范错误 VueCli 自定义创建项目 安装脚手架 (已安装) npm i vue/cli -g创建项目 vue create xxx选项 Vue CLI v5.0.8 ? Please pick a preset:Default ([Vue 3] babel, eslint)Default ([Vue 2] babel, eslint) …

lodash常用方法合集

安装lodash 建议安装lodash-es&#xff0c;lodash-es 是 lodash 的 es modules 版本 &#xff0c;是着具备 ES6 模块化的版本&#xff0c;体积小。按需引入。 示例 npm i lodash-es import { chunk,compact } from lodash-es; /**按需引入*/ 1.chunk 数组分组 chunk(arra…

06、Python 序列 与 列表 与 元组 的关系和创建 和 简单使用

目录 序列元组与列表关系总结 创建元组与列表方式一创建元组注意点 创建元组与列表方式二简单使用通过索引访问元素子序列序列加法序列乘法in运算 了解Python序列 创建列表和元组 通过索引访问元素 子序列 序列运算 序列 所谓序列&#xff0c;指的是一种包含多项数据的数据结…

通义大模型使用指南之通义千问

一、注册 我们可以打开以下网站&#xff0c;用手机号注册一个账号即可。 通义大模型 (aliyun.com) 二、使用介绍 如图&#xff0c;我们可以看到有三个大项功能&#xff0c;通义千问、通义万相、通义听悟。下来我们体验一下通义千问的功能。 1、通义千问 通义千问主要有两个功能…

Yet Another mod M

题目传送门 引 总结一下&#xff0c; 绝对众数 随机化 绝对众数随机化 绝对众数随机化 ,虽然这么说有点套路&#xff0c;但还是多这么想想 解法 如果有答案&#xff0c;我们随机一个数 a i a_i ai​ , 那么 a i a_i ai​ 满足 a i x ( m o d M ) a_i x \quad(mod \q…

ROI的投入产出比是什么?

ROI的投入产出比是什么&#xff1f; 投入产出比&#xff08;Return on Investment, ROI&#xff09;是一种评估投资效益的财务指标&#xff0c;用于衡量投资带来的回报与投入成本之间的关系。它的计算公式如下&#xff1a; 投资收益&#xff1a;指的是投资带来的净收入&#x…

MFC Windows 程序设计[330]之表头控件例程(附源码)

MFC Windows 程序设计[330]之表头控件例程 程序之美前言主体运行效果核心代码逻辑分析结束语程序之美 前言 MFC是微软公司提供的一个类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含大量Wind…

【iOS】JSONModel的基本使用

文章目录 前言一、导入JSONModel二、JSONModel的基本使用1.基本用法2.模型集合3.模型导出为NSDictionary或JSON4.设置所有属性可选&#xff08;所有属性值可以为空&#xff09;5.下划线(蛇式)转驼峰命名法 前言 JSONModel 是一个用于 Objective-C 的开源库&#xff0c;它用于简…

MQTT协议简介及其应用

一、简介 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输&#xff09;是一种基于发布/订阅模式的“轻量级”通讯协议&#xff0c;该协议构建于TCP/IP协议上&#xff0c;由IBM在1999年开发。MQTT最大的优点在于&#xff0c;能够以极低的带宽…
最新文章