spring事务详解
事务管理方式
在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理两种方式。
- 编程式事务管理: 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
- 声明式事务管理: 建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。 声明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,更快捷而且简单,推荐使用。
编程式事务管理:
1、使用 TransactionTemplate 来管理事务:
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {try {// .... 业务代码} catch (Exception e){//回滚transactionStatus.setRollbackOnly();}}});
}
2、使用 TransactionManager 来管理事务:
@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction() {TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());try {// .... 业务代码transactionManager.commit(status);} catch (Exception e) {transactionManager.rollback(status);}
}
声明式事务管理:
@Transactionalpublic void testTransactional(){}
事务提交方式
默认情况下,数据库处于自动提交模式。
每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。
对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。
不过,这个我们不用担心,spring会将底层连接的自动提交特性设置为false。
也就是在使用spring进行事物管理的时候,spring会将是否自动提交设置为false,等价于JDBC中的 connection.setAutoCommit(false);,在执行完之后在进行提交,connection.commit(); 。
事务隔离级别
隔离级别是指若干个并发的事务之间的隔离程度。
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
- TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
- TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。
- TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。
- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
事务传播行为
当事务方法被另外一个事务方法调用时,必须指定事务应该如何传播,例如,方法可能继续在当前事务中执行,也可以开启一个新的事务,在自己的事务中执行。
- TransactionDefinition.PROPAGATION_REQUIRED:默认的事务传播行为,指的是如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。更确切地意思是: 如果外部方法没有开启事务的话,Propagation.REQUIRED 修饰的内部方法会开启自己的事务,且开启的事务相互独立,互不干扰。 如果外部方法开启事务并且是 Propagation.REQUIRED 的话,所有 Propagation.REQUIRED 修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务都需要回滚。
也就是说如果a方法和b方法都添加了注解,在默认传播模式下,a方法内部调用b方法,会把两个方法的事务合并为一个事务。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都会开启自己的事务,且开启的事务与外部的事务相互独立,互不干扰。当类A中的 a 方法用默认 Propagation.REQUIRED模式,类B中的 b方法加上采用 Propagation.REQUIRES_NEW模式,然后在 a 方法中调用 b方法操作数据库,然而 a方法抛出异常后,b方法并没有进行回滚,因为Propagation.REQUIRES_NEW会暂停 a方法的事务 ,总结就是a不影响b,b影响a
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
事务回滚规则
指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。
spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
可以明确的配置在抛出那些异常时回滚事务,包括checked异常。
也可以明确定义那些异常抛出时不回滚事务。
事务常用配置
- 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 : 该属性用于设置事务的传播行为。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)。
- isolation:该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置。
- timeout:该属性用于设置事务的超时秒数,默认值为-1表示永不超时。也就是指一个事务所允许执行的最长时间,如果在超时时间内还没有完成的话,就自动回滚。假如事务的执行时间格外的长,由于事务涉及到对数据库的锁定,就会导致长时间运行的事务占用数据库资源。
@Transaction失效场景
1、访问权限问题 (只有public方法会生效)
java的访问权限主要有四种:private、default、protected、public,它们的权限从左到右,依次变大。spring要求被代理方法必须得是public的。
我们自定义的事务方法如果它的访问权限不是public,会导致事务失效。
@Transactionalprivate void testTransactional() {}
2、方法用final修饰,不会生效
有时候,某个方法不想被子类重新,这时可以将该方法定义成final的。
普通方法这样定义是没问题的,但如果将事务方法定义成final,会导致事务失效
@Transactionalpublic final void testTransactional() {}
3、同一个类中的方法直接内部调用,会导致事务失效
@Service
public class TransactionalTest implements TransactionalService{@Overridepublic void testTransactional() {transactional();}@Transactionalpublic void transactional(){}
}
文章开头说道,声明式事务管理是建立在AOP之上的。AOP的实现原理是动态代理。
一个方法调用本类的其他方法是不会走代理,原因是在InvocationHandlerImpl#invoke中method.invoke(subject, args);
这里调用的是目标类subject的方法,直接执行目标类方法,不会执行代理类的方法。
因为JDK动态代理采用的是接口实现的方式,通过反射调用目标类的方法,此时如果调用本类的方法,this指的是目标类,并不是代理类所以不会走代理。
不走代理,事务自然会失效。
编写新的sevice
这个方法非常简单,只需要新加一个Service方法,把@Transactional注解加到新Service方法上,把需要事务执行的代码移到新方法中。
自己注入自己
@Service
public class TransactionalTest implements TransactionalService{@Resourceprivate TransactionalTest transactionalTest;@Overridepublic void testTransactional() {transactionalTest.transactional();}@Transactionalpublic void transactional(){}
}
如果不想再新加一个Service类,在该Service类中注入自己。
完全不用担心循环依赖的问题,spring ioc内部的三级缓存保证了它,不会出现循环依赖问题。
4、事务方法中使用try-catch捕获处理
@Transactionalpublic void transactional(){try{....}catch(Exception e){logger.error("",e);}}
事务@Transactional由spring控制时,它会在抛出异常的时候进行回滚。如果自己使用try-catch捕获处理了,是不生效的。
如果想事务生效可以进行手动回滚或者在catch里面将异常抛出【throw new RuntimeException();】
事务手动回滚
try{...
}catch(Exception e){log.error("fail",e);TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();return false;
}
回滚部分异常 使用【Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint(); 】设置回滚点。
使用【TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);】回滚到savePoint。
@Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){ success(); //只回滚以下异常,Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();try { exception(); } catch (Exception e) { e.printStackTrace(); // 手工回滚事务TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);return response.error();} return response.success();
}
相关文章:
spring事务详解
事务管理方式 在Spring中,事务有两种实现方式,分别是编程式事务管理和声明式事务管理两种方式。 编程式事务管理: 编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,sp…...
LIMS系统的核心功能有哪些
LIMS实验室管理系统,是一种利用信息化技术管理和优化实验室工作流程的系统。其核心功能主要包括以下几个方面: 一、样品管理 样品登记与追踪:LIMS系统能够对实验室内的所有样品进行统一管理,包括样品的接收、登记、分类、追踪和管…...

jenkins在使用pipeline时,为何没有方块形视图
项目场景: 安装完Jenkins时后,通过pipeline创建的项目任务。 问题描述 在立即构建后,没有显示每个阶段的视图。 原因分析: 原因是,刚安装的Jenkins,这个视图不是Jenkins自带的功能,而必须安装…...

Desktop docker 部署 WordPress
Desktop Docker 部署 WordPress 之前都是在Linux里面玩的,今天看到别人在windwos下安装docker,一时兴起装了一个试试,效果一般,很吃硬盘空间和内存。 首先在docker官方下载桌面版,安装下一步一直到完成。 安装完docke…...

简单的找到自己需要的flutter ui 模板
简单的找到自己需要的flutter ui 模板 网站 https://flutterawesome.com/ 简介 我原本以为会很难用 实际上不错 很简单 打开后界面类似于,右上角可以搜索 点击view github 相当简单 很oks...

SpringBoot实现多数据源切换
1. 概述 仓库地址:https://gitee.com/aopmin/multi-datasource-demo 随着项目规模的扩大和业务需求的复杂化,单一数据源已经不能满足实际开发中的需求。在许多情况下,我们需要同时操作多个数据库,或者需要将不同类型的数据存储在不…...
VUE + 小程序 关于前端循环上传附件页面卡死的问题
最开始我使用for循环,后端能正常保存,但是前端页面卡死了,开始代码是这么写的 wx.showLoading({title: 文件上传中...,mask: true // 是否显示透明蒙层,防止触摸穿透,默认:false});const {fileList} that.…...

【基础算法总结】分治—归并
分治—归并 1.排序数组2.交易逆序对的总数3.计算右侧小于当前元素的个数4.翻转对 点赞👍👍收藏🌟🌟关注💖💖 你的支持是对我最大的鼓励,我们一起努力吧!😃😃 1.排序数组 …...

基于Java+SpringMvc+Vue技术的实验室管理系统设计与实现(6000字以上论文参考)
博主介绍:硕士研究生,专注于信息化技术领域开发与管理,会使用java、标准c/c等开发语言,以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年,拥有近12年的管理工作经验,拥有较丰富的技术架…...

19_谷歌GoogLeNet(InceptionV1)深度学习图像分类算法
1.1 简介 GoogLeNet(有时也称为GoogleNet或Inception Net)是一种深度学习架构,由Google的研究团队在2014年提出,主要设计者为Christian Szegedy等人。这个模型是在当年的ImageNet大规模视觉识别挑战赛(ILSVRC…...

clickhouse高可用可拓展部署
clickhouse高可用&可拓展部署 1.部署架构 1.1高可用架构 1.2硬件资源 部署服务 节点名称 节点ip 核数 内存 磁盘 zookeeper zk-01 / 4c 8G 100G zk-02 / 4c 8G 100G zk-03 / 4c 8G 100G clikehouse ck-01 / 32c 128G 2T ck-02 / 32c 128G 2T ck-03 / 32c 128G 2T ck-04 /…...

QT中QDomDocument读写XML文件
一、XML文件 <?xml version"1.0" encoding"UTF-8"?> <Begin><Type name"zhangsan"><sex>boy</sex><school>Chengdu</school><age>18</age><special>handsome</special>&l…...

sql盲注
文章目录 布尔盲注时间盲注 布尔盲注 介绍:在网页只给你两种回显的时候是用,类似于布尔类型的数据,1表示正确,0表示错误。 特点:思路简单,步骤繁琐且麻烦。 核心函数: length()函数substr()函…...

星网安全产品线成立 引领卫星互联网解决方案创新
2024年6月12日,盛邦安全(688651)成立星网安全产品线,这是公司宣布全面进入以场景化安全、网络空间地图和卫星互联网安全三大核心能力驱动的战略2.0时代业务落地的重要举措。 卫星互联网技术的快速发展,正将其塑造为全球…...
Adam自适应动量优化算法
Adam(Adaptive Moment Estimation)是一种结合了动量法和自适应学习率思想的优化算法,特别适用于训练神经网络和深度学习模型。以下是对Adam调整学习率的详细介绍及具体例子。 一、Adam调整学习率介绍 自适应学习率: Adam算法的核…...
Mac OS系统中Beyond Compare 4破解方式
文章出处 https://blog.csdn.net/qq_42418042/article/details/137544113 前言 记录实操过程,以防以后找不到了~ 实际原理是启动时删除文件,实现无限试用 实操过程 下载安装包 官网链接 https://www.scootersoftware.com/download.php 解压、移动到应…...

6000元最好的家用投影仪:当贝X5S Pro六千元配置最高画质最强
数码家电品牌发展迅速,投影同样也是一种更新迭代较快的产品类型,有时候去年还比较火的产品,今年就会被别的产品取代,就比如之前灯泡投影一直被认为是好产品的代表,但是现在国产激光投影的销量反而更高。一般来说6000元…...

#### golang中【堆】的使用及底层 ####
声明,本文部分内容摘自: Go: 深入理解堆实现及应用-腾讯云开发者社区-腾讯云 数组实现堆 | WXue 堆(Heap)是实现优先队列的数据结构,Go提供了接口和方法来操作堆。 应用 package mainimport ("container/heap&q…...

OpenAI Gym Atari on Windows
题意:在Windows系统上使用OpenAI Gym的Atari环境 问题背景: Im having issues installing OpenAI Gym Atari environment on Windows 10. I have successfully installed and used OpenAI Gym already on the same system. It keeps tripping up when t…...
Java进阶----接口interface
接口 接口概述 接口是一种规范,使用接口就代表着要在程序中制定规范. 制定规范可以给不同类型的事物定义功能,例如: 利用接口,给飞机、小鸟制定飞行规范,让其都具备飞行的功能;利用接口,给鼠…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...