运用@Transactional,自己抛出异常时不会回滚的原因

2023-11-15



近日测试用例,发现这样一个现象:


在业务代码中,有如下两种情况,比如:
throw new RuntimeException("xxxxxxxxxxxx"); 事务回滚
throw new Exception("xxxxxxxxxxxx"); 事务没有回滚

 

自以为很了解事务,或许时间久远的缘故,没分析出来何故,遂查阅了下资料,写下了如下的内容,供参考:

 

1).Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。也就是默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚, “将异常捕获,并且在catch块中不对事务做显式提交=生吞掉异常” ,要想捕获非运行时异常则需要如下配置:

解决办法:
1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。
2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
     <tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
   </tx:attributes>
 </tx:advice>
 
或者
定义不会滚的异常


<tx:advice id="txAdvice">
    <tx:attributes>
       <tx:method name="update*" no-rollback-for="IOException"/>
       <tx:method name="*"/>
    </tx:attributes>
 </tx:advice>

 
2).spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常).
 如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。 
 一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。
 
如:
try  
    //bisiness logic code  
catch(Exception e)  
    //handle the exception  
 

 由此可以推知,在spring中如果某个业务方法被一个 整个包裹起来,则这个业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致spring异常抛出触发事务回滚策略失效。
 不过,如果在catch代码块中采用页面硬编码的方式使用spring api对事务做显式的回滚,这样写也未尝不可。
 
 3).基于注解的事务:

 Transactional的异常控制,默认是Check Exception 不回滚,unCheck Exception回滚
 如果配置了rollbackFor 和 noRollbackFor 且两个都是用同样的异常,那么遇到该异常,还是回滚
 rollbackFor 和noRollbackFor 配置也许不会含盖所有异常,对于遗漏的按照Check Exception 不回滚,unCheck Exception回滚

近日测试用例,发现这样一个现象:


在业务代码中,有如下两种情况,比如:
throw new RuntimeException("xxxxxxxxxxxx"); 事务回滚
throw new Exception("xxxxxxxxxxxx"); 事务没有回滚

 

自以为很了解事务,或许时间久远的缘故,没分析出来何故,遂查阅了下资料,写下了如下的内容,供参考:

 

1).Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。也就是默认对RuntimeException()异常或是其子类进行事务回滚;checked异常,即Exception可try{}捕获的不会回滚,如果使用try-catch捕获抛出的unchecked异常后没有在catch块中采用页面硬编码的方式使用spring api对事务做显式的回滚,则事务不会回滚, “将异常捕获,并且在catch块中不对事务做显式提交=生吞掉异常” ,要想捕获非运行时异常则需要如下配置:

解决办法:
1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。
2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
     <tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
   </tx:attributes>
 </tx:advice>
 
或者
定义不会滚的异常


<tx:advice id="txAdvice">
    <tx:attributes>
       <tx:method name="update*" no-rollback-for="IOException"/>
       <tx:method name="*"/>
    </tx:attributes>
 </tx:advice>

 
2).spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常).
 如果抛出runtime exception 并在你的业务方法中没有catch到的话,事务会回滚。 
 一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据.所以你的catch代码是画蛇添足。
 
如:
try  
    //bisiness logic code  
catch(Exception e)  
    //handle the exception  
 

 由此可以推知,在spring中如果某个业务方法被一个 整个包裹起来,则这个业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出!全被捕获并吞掉,导致spring异常抛出触发事务回滚策略失效。
 不过,如果在catch代码块中采用页面硬编码的方式使用spring api对事务做显式的回滚,这样写也未尝不可。
 
 3).基于注解的事务:

 Transactional的异常控制,默认是Check Exception 不回滚,unCheck Exception回滚
 如果配置了rollbackFor 和 noRollbackFor 且两个都是用同样的异常,那么遇到该异常,还是回滚
 rollbackFor 和noRollbackFor 配置也许不会含盖所有异常,对于遗漏的按照Check Exception 不回滚,unCheck Exception回滚

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

运用@Transactional,自己抛出异常时不会回滚的原因 的相关文章

  • Akka 和 spring 配置

    我正在尝试将 akka 与 spring 结合起来 但没有成功 基本上 我的应用程序似乎不习惯读取 akka 模式 具有架构的 service context xml 的一部分
  • 在Spring-Boot中,我们如何在同一个项目中连接两个数据库(Mysql数据库和MongoDB)?

    我正在尝试创建一个 Spring Boot 项目 其中我有一个要求 我想连接到不同的数据库 MySql 和 MongoDB 我是否需要做一些特殊的事情来连接到这两个数据库 或者 spring boot 会自动计算出自己连接到这两个数据库 我
  • 在 Spring 4 中干掉通用的 RedisTemplate

    我读到你可以拥有 Autowired从 Spring 4 开始泛型 这太棒了 我有一个摘要RedisService我想参加的课程 Autowired一个通用的 RestTemplate 如下所示 public abstract class
  • AngularJs 表单发布数据在我的 spring 控制器中给出空值

    大家好 我正在尝试使用 Angular 发布表单 但我在 Spring 控制器中收到空值 此外 在我的控制台中 我看到 sysout 的空值 此外 即使我看到 bull 打印在我的控制台上 我也会收到错误警报 我的 JS 控制器 angul
  • JSON:@Transient 字段未序列化

    我有一个域类 Loan java 其中有一个未持久化的字段 JsonInclude Transient private LoanRating loanRating Public Getters and setters for that fi
  • Spring Security匿名用户可以访问每个url

    我正在开发 gwt 应用程序 我想使用 spring security 来保护它 我在数据库中有用户数据 UserService 负责获取特定用户 我已经关注了这个tutorial http www javacodegeeks com 20
  • 需要 Spring 3 JSF 2 集成示例

    我想将 Spring 3 Web Flow 2 JSF 2 集成在一起 我需要您向我推荐一个好的教程或示例 提前致谢 UPDATE 我使用了以下示例 它对我来说运行良好 没有任何问题 http www mkyong com jsf2 jsf
  • 如何在NodeJs中应用Java/Spring的分层架构?

    我已经尝试学习 NodeJS 有一段时间了 所有书籍和教程似乎都遵循类似的代码结构模式 例子 const express require express const app express app set view engine hbs a
  • 如何为Spring Boot中的所有控制器指定前缀?

    我有控制器映射到 user and order RestController RequestMapping users public class UserController RestController RequestMapping or
  • 如何从 Jackson 中的自定义解串器调用默认解串器

    我在杰克逊的自定义解串器有问题 我想访问默认序列化器来填充我要反序列化的对象 在填充之后 我将做一些自定义的事情 但首先我想使用默认的 Jackson 行为反序列化对象 这是我目前拥有的代码 public class UserEventDe
  • Spring Security登录返回404

    我目前正在使用 Spring 框架开发我的博客 我正在实现 Spring Security 用于登录目的 一切都按预期进行 直到我提交始终返回 404 代码的登录凭据 这是我的 web xml 代码e
  • Spring Redis 排序键

    我在 Redis Spring Data Redis 中有以下键 localhost gt Keys 1 id 1 Name C5796 Site DRG1 2 id 2 Name CX1XE Site DG1 3 id 3 Name C5
  • 使用 REST API 实现属性/字段级安全

    我正在为支持多租户授权模型的 REST API 构建概念验证 该模型不仅控制用户可以访问哪些对象 还控制对象中的字段 此模型的目标是确保租户管理员只能修改其租户并且只能查看允许的对象属性 我有一个正在开发的现有代码库 可在以下位置公开获取
  • 是否有适合 Java 1.4 和 SE (Swing) 应用程序的优秀 DI 框架?

    我正在寻找一个适用于在 JDK 1 4 下运行的 Java SE Swing 应用程序的依赖注入框架 有没有我可以使用的推荐 DI 框架 Guice 和其他基于注释的框架已经退出 我不想搞乱像 Retroweaver 这样的东西 另外 Sp
  • 访问 webapp 外部的文件(Tomcat V6 和 Spring)

    我提供上传图像的选项 并且图像正在上传到 opt uploads contactImages 在 Windows 中为 C opt uploads contactImages 我想在我的 JSP 中显示图像 为此 我尝试通过在主机标签下添加
  • 使用 Spring Batch 将文件中的日期解析为 LocalDateTime

    我正在尝试使用 Spring Batch 读取包含日期的 CSV 文件 但在将日期解析为LocalDateTime Object 字段 日期 上的对象 目标 中的字段错误 拒绝值 2017 07 20 04 15 25 0 代码 typeM
  • 集群环境下如何管理spring缓存

    我正在尝试使用 spring 为我的应用程序构建缓存服务 缓存需要从数据库填充 我的应用程序在三个节点上运行 并希望所有三个节点都与缓存同步 如果一个节点在缓存中获得更新的值 它应该通知其他节点 我在看Spring 缓存抽象 http do
  • Spring动态(可扩展)列表形式

    我在春季遇到动态表单问题 在我们的表单中 我们要指定一个标题 并添加一些问题 我们有一个 添加 按钮来添加问题输入表单 jquery 当需要时 我们的表格有一个问题字段 每次都会添加额外的字段 按下 添加 按钮 提交时似乎没有额外的字段 已
  • 使用 Spring MVC 在 jar 文件中显示 jsp 页面

    我正在使用 Spring MVC 3 2 2 在 java 中开发一个 Web 应用程序 我在从 jar 文件中加载 jsp 页面时遇到问题 Spring MVC Web应用程序具有以下结构 META INF WEB INF spring
  • Spring Data Jpa OneToMany 同时保存子实体和父实体?

    这是我的父实体 注意 为了简洁起见 删除了 getter setter lombok 注释 Entity public class Board Id GeneratedValue strategy GenerationType IDENTI

随机推荐

  • centos7 安装jdk17

    默认情况下 yum 仓库中是没有jdk 17 的 只有jdk 11 所以我们不能直接用yum 安装 需要手动下载进行配置工作 下载文件 wget https download oracle com java 17 latest jdk 17
  • 网页与服务器数据库数据交互,网页与ACCESS数据库如何实现数据交互?

    1 打开access 单机菜单栏创建 选择表 单击列 选择下拉菜单中的字段类型 单机列名更改字段名称 2 添加完成后单击保存成test accdb 新建c 窗体程序 3 using System using System Collectio
  • 今日算法中数据结构知识练习 (7-19)【4】

    Date 2019 07 19 1 两个指针 P 和 Q 分别指向单链表的两个元素 P 所指元素是 Q 所指元素前驱的条件是 P gt next Q 2 串是一种特殊的线性表 其特殊性体现在 数组元素是一个字符 3 下列文件中属于逻辑结构文
  • uniapp onHide()和onUnload()的使用

    小程序onHide 和onUnload onHide 触发的场景 导航页1 gt gt 导航页2 会触发导航页1 onHide 导航页 gt gt 子页面 会触发导航页 onHide 子页面1 gt gt 子页面2 会触发子页面1 onHi
  • linux查询mysql内存使用率_MySQL内存使用率无限增长

    背景 收到内存报警的信息以后 从监控中发现MySQL服务器的内存使用率在不断的增长 附图 虽然进行了重启 但是内存占用率依然会不停的增长 大约在半个月左右的时间内又把内存消耗完毕 场景 未搭建场景 数据库版本 5 7 12 分析 PS 时间
  • 精简CUDA教程——CUDA Runtime API

    精简CUDA教程 CUDA Runtime API tensorRT从零起步迈向高性能工业级部署 就业导向 课程笔记 讲师讲的不错 可以去看原视频支持下 Runtime API 概述 环境 图中可以看到 Runtime API 是基于 Dr
  • (C语言)在屏幕上输出对应的图案(* ** *** *****.....)

    在屏幕上输出如下的图案 根据上面图片可以看出来 前7行中下一行的星比前一行多出两个星 第8行到第13行是下一行比前一行少2个星 代码为 include
  • el-select远程搜索:remote-method遇到的坑

    在使用远程搜索的时候 就是每次发请求获取数据然后选择 会出现选择后总是会出现选择紊乱的情况 在使用debugger后排查了很久 发现每次选择内容后 都会触发 remote method这个事件 也就是继续会发请求 然后获取到新的数据重新赋值
  • 什么是值传递,什么是引用传递

    一般认为 java中基础类型数据传递都是值传递 java中实例对象的传递是引用传递 值传递是对基本型变量而言 传递的是该变量的一个副本 不影响该原变量 而引用传递是一般对于对象型变量而言 传递的是该对象地址的副本 并不是原对象本身 1 值传
  • linux bash环境配置文件

    linux bash环境配置文件 你是否会觉得奇怪 怎么我们什么动作都没有进行 但是一进入 bash 就取得一堆有用的变量了 这 是因为系统有一些环境配置文件案的存在 让 bash 在启动时直接读取这些配置文件 以规划好 bash 的操作环
  • ubuntu切换国内镜像源,加速apt-get下载速度

    ubuntu切换国内镜像源 加速apt get下载速度 如题 使用apt get命令安装包时 由于系统自带的下载源在国外服务器上 故下载速度较慢 若切换为国内源 将显著提升下载速度 下列是设置步骤 STEP 1 查找适合自己系统的镜像源配置
  • 深入理解线程的原理和用法

    Java中的线程 程序 进程和线程 1程序是一段静态的代码 它是应用程序执行的蓝本 2进程是程序的一次动态执行过程 它对应了从代码加载 执行到执行完毕的一个完整过程 作为蓝本的程序可以被多次加载到系统的不同内存区域分别执行 形成不同的进程
  • 某某analysis参数算法分析

    作者 TheWeiJun 来源 逆向与爬虫的故事 今天给大家带来一个干货分享 由于想要查看某些APP的详细信息 需要通过APP名称去某麦网站进行搜索查看 而整个过程中涉及到逆向分析 为了方便大家学习 本次完整流程记录如下 目录 一 确定要获
  • java可变参数函数_Java 变参函数的实现

    Java的变参函数实现实际上参数是一个数组 其简单用法如下 public class variableParamTest private static void variableParam Object args for Object v
  • vue实现任务周期cron表达式选择组件

    vue cron表达式 Cron表达式的详细用法 vue cron 基于vue的cron表达式组件 项目开发过程中遇到了需要在from表单输入cron表达式的情况 但对cron表达式没有深刻了解的用户来说 输入一个正确的cron表达式有些困
  • 实现文件上传进度条及解决request.upload.addEventListener in not a function问题

    使用axios上传文件时需要进度条 可通过监听axios的onUploadProgress获取当前文件上传进度 进度条可以用antd的Progress 实现过程中出现问题request upload addEventListener in
  • 关于Hadoop分布式计算:多个Map分布在不同节点上执行

    1 背景 问题 学习Hadoop已经快一年了 也是似懂非懂的样子 由于项目的原因 再次启动Hadoop 一直以为这个很简单就能够实现多个机器一起完成一个任务 其实并不然 在实验过程中 发现Map的数量并不能通过设置 mapreduce jo
  • 一文详解APS能做什么?不能做什么?

    APS Advanced Planning Scheduling 被翻译成 高级计划排程 我觉得似乎advance用在这里应该是 进阶 的意思 就是在原来手工作业或者MRP MRPII基础进了一步 高级 总觉得是高大上 而APS就是一个辅助
  • Maya删除被锁定的节点

    问题描述 在Maya中如果节点被锁定 则无法被修改或删除 这种情况下需要通过Maya的命令对节点的状态进行修改 解决方法 首先选中被锁定的节点 然后在Python脚本编辑器中执行以下的代码 import maya cmds as mc li
  • 运用@Transactional,自己抛出异常时不会回滚的原因

    近日测试用例 发现这样一个现象 在业务代码中 有如下两种情况 比如 throw new RuntimeException xxxxxxxxxxxx 事务回滚 throw new Exception xxxxxxxxxxxx 事务没有回滚 自