Spring接口方法加@Transactional失效的原因解析

Spring中什么时候@Transactional会失效 自调用、非 public、异常没抛、线程跨域、配置不到位建议:所有方法都写在 public方法上不要在构造器中调用事务方法自调用的情况提取成一个新的@Service类想对。 阅读详情

问题

今天项目测试一个方法的时候,发现日志报错,日志报错大致如下:Connection is read-only. Queries leading to data modification are not allowed

org.springframework.dao.TransientDataAccessResourceException:
### Error updating database.  Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
### The error may involve com.o2o.app.repository.AccountOrderMybatisDao.updateOrder-Inline
### The error occurred while setting parameters
### SQL: UPDATE t_account_order SET ORDER_STATUS=?, STATUS_DESCRIPTION=?, IS_DELETE = ?           WHERE  TRADE_CODE = ? and TRADE_TYPE=?
### Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed; SQL []; Connection is 
read-only. Queries leading to data modification are not allowed; nested exception is java.sql.SQLException: 
Connectionis read-only. Queries leading to data modification are not allowed

第一眼看上去,这不是Spring事务配置了只读事务属性,当执行sql写操作当然会失败了,为了更好解决这个bug,让我们先温习一下事务以及Spring在事务传播做了那些事?

  • 事务介绍
    事务(Transaction):指的是要做的事情,在计算机术语指的是访问并能更新数据库数据的一个程序执行单元
    由于我们日常开发,需要经常对关系型数据库打交道,这里简单介绍一下关系型数据库的事务四大属性
事务名称解释
原子性(Atomicity)事务是一个原子操作,原子操作简单理解指的是这个操作要么全部成功,要么全部失败
一致性(Consistency)事务无论成功与否,数据库必须保证所处的数据不应被破坏,举个例子:A给B无论成功或失败转账,那么A的钱+B的钱前后应该总和相等
隔离性(Isolation)同一份的数据可能有很多事务进行操作,因此要将各种事务隔离开,防止数据被损坏
持久性(Durability)事务如果一旦完成,结果都应不变,因为这样无论系统发送了什么错误,都能进行数据恢复
  • Spring事务核心类和接口
    如下图所示:在spring-tx包下有三个spring事务管理非常重要的接口 : PlatformTransactionManager,TransactionDefinition,TransactionStatus
    spring事务管理接口
    spring并不实现各个数据库持久层的事务实现,而是提供对应的事务管理器,如下图所示:
    Spring事务实现方式
    我们首先查看PlatformTransactionManager接口的源代码:
    在这里插入图片描述
  • TransactionStatus getTransaction(TransactionDefinition definition)
    官方的解释是: Return a currently active transaction or create a new one, according to the specified propagation behavior,这句话的意思是根据指定的事务行为,返回当前的事务或者新建一个事务。
  • void commit(TransactionStatus status)
    官方解释是:Commit the given transaction, with regard to its status. If the transaction has been marked rollback-only programmatically, perform a rollback. 这句话的意思是根据事务的状态提交事务,如果事务标记了rollback-only,请执行会滚。
  • void rollback(TransactionStatus status)
    官方的解释是: Perform a rollback of the given transaction,即对事务进行回滚。
    看到这里,我们需要明确三个接口中入参的TransactionDefinition是个什么东西呢?
    让我们先大致查看一下TransactionDefinition接口的方法和成员变量,以下将会对此接口的方法做个简单的介绍,如下图所示:
    在这里插入图片描述
  • 事务的传播行为
    当事务方法被调用时候,必须指定事务如何传播,下面是事务传播行为的介绍:
事务名称解释
PROPAGATION_REQUIRED支持当前的事务,如果当前事务不存在就新建一个事务
PROPAGATION_SUPPORTS支持当前事务,如果事务不存在,将以非事务方式运行
PROPAGATION_MANSATORY支持当前事务,如果事务不存在将抛异常
PROPAGATION_REQUIRES_NEW如果当前事务存在,将当前事务挂起并创建新的事务,如果当前事务不存在就新建一个事务
PROPAGATION_NOT_SUPPORTED不支持当前事务,以非事务的方式运行
PROPAGATION_NEVER不支持当前事务,如果当前事务存在就抛异常
PROPAGATION_NESTED如果当前事务存在,则执行一个内嵌的事务
  • 事务的隔离级别
    典型的事务隔离不同所造成问题如下:
  1. 脏读:脏读发送在A事务读取B事务已经改写但是还未提交的数据,若此时B事务回滚了,那么A事务获取就是脏数据
  2. 不可重复读:不可重复读发送在当A事务执行2次查询,每一次获取的数据结果都不相同,这是由于B事务在A事务2次查询期间进行了更新
  3. 幻读: 幻读发送在当A事务读取了几行数据,紧接着B事务进行输入的插入,在随后的查询中A事务就会读了原本不存在的记录
    ⚠️ 不可重复读特指修改的记录,而幻读指的是新增或删除的记录
  • 只读属性
    如果设置了只读事务,只读事务常常用于做查询使用,此时的增删改,将会报Connection is read-only. Queries leading to data modification are not allowed的异常。
  • 事务的超时
    一个正常和良好的程序,事务的行为时间并不会很长,较长的事务运行时间,会占用数据库资源,所以这里就设置超时时间,若指定时间内没有执行完事务,将会自动进行回滚
  • 事务的名称
    在一个事务行为中配置获取事务的名称,如我们常见的save,add,del 等等…

以上温习过Spring事务管理器和传播行为后,所以既然报错Connection is read-only. Queries leading to data modification are not allowed所以我们在接口方法的实现,加了以下的注解: @Transactional(propagation = Propagation.REQUIRED, readOnly = false),but!当我再次请求接口的时候,发现依然还是报同样的错误,百度以下,发现有相关问题博客的收集:Spring 下默认事务机制中@Transactional 无效的原因

Method visibility and @Transactional When using proxies, you should apply the @Transactional annotation 
only to methods with public visibility. If you do annotate protected, private or package-visible methods with the
@Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. 
Consider the use of AspectJ (see below) if you need to annotate non-public methods.

大概意思是:如果你是使用默认的Spring Aop代理方式将@Transaction注解应该用于公共可见即public的,如果对protected,或者private的方法加入@Transaction注解,则会无效。如果想在私有方法是使事务有效,可以用AspectJ进行实现。
but,我们的注解没有加在protected和private方法上,但是依然无效,why?此次注解失效原因像下面简单的例子一样:在电商系统中,存在待支付的订单,假设有一个订单编号为201904191102的订单要进行支付,首先我需要刷新支付页面,就需要调用收银台接口,由于一直使用的scala开发,所以下面的代码使用scala做演示:

  /**
    * 刷新收银台的接口:refreshCashier
    */
  def refreshCashier(orderId: String): OrderInfo
  
    /**
    * 更新钱包的方法
    */
  def updateWallet(order:orderInfo):PayDto
  
  override def refreshCashier(orderId: String): OrderInfo = {
    // 伪代码,在这个方法里面调用 updateWallet方法
  }
 @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
  override def updateWallet(order:orderInfo): PayDto = {
   // 这里发送了异常
   throw new AppException()
  }

在上面的代码中,refreshCashier方法调用了updateWallet方法的时候,当updateWallet方法出错报异常,事务并没有回滚,这是因为Spring Aop动态代理会为每个class对象生成代理对象,只有在代理对象之间进行调用的时候,将会触发切面相关的逻辑处理。所以要保证整个方法调用链的事务性,在refreshCashier方法加上@Transaction注解,此时才能保证,updateWallet方法出错时候,整个方法能进行事务的回滚。这样完美,问题解决了.

java——@Transactional 在哪些情况下会失效? Transactional注解在Spring框架中用于声明式事务管理,确保数据的一致性和可靠性。然而,在某些情况下,@Transactional注解可能会失效。通过遵循这些原则,可以最大程度地确保@Transactional注解在Spring框架中的正确性和有效性。 阅读详情

相关推荐

Spring事物注解@Transactional失效场景

概述 @Transactional注解相信大家都不陌生,平时在开发中spring框架中经常用到的事物注解。 他的作用就是控制程序执行的原子性,保证程序要提交就一起提交,如果出现错误,则一起进行回滚操作。 但是在使用@Transactional注解的时候有很多需要注意的地方,不然你就会发现这个事物注解会出现失效的情况。 在spring程序中如何去管理事物 事物管理在系统开发中是不可缺少的,在spri...

justLym的博客 3898

出现java.sql.SQLException: Connection is read-only. Queries leading to data modification are not

例如,如果你没有正确地启用事务,或者你的事务没有正确地提交,可能会导致数据库连接是只读的。数据库配置错误:如果你的数据库配置不正确,可能会导致数据库连接是只读的。例如,如果你的数据库服务器没有启动,或者你的数据库连接配置不正确,可能会导致数据库连接是只读的。数据库访问权限错误:如果你没有足够的数据库访问权限,可能会导致数据库连接是只读的。例如,如果你没有足够的权限执行修改操作,可能会导致数据库连接是只读的。数据库连接是只读的:如果你的数据库连接是只读的,那么你就无法执行修改操作。

qq_22547153的博客 9675

Spring 事务方法与非事务方法相互调用 @Transactional 注解失效分析

写这篇文章的初衷是因为在实用Spring事务的时候,我在A方法中调用了B方法和C方法,原意是想如果B方法中报错,则回滚B方法;如果C方法中异常,则只回滚C方法,B方法和C方法不会相互影响。于是我在B方法和C方法上加了@Transactional注解,A没有加。结果测试发现结果并非所想。于是便分析了一番,现将分析结果做个分享: 1、spring事务的传播机制及原因分析 要知道上面原因产生的原因,则首先得知道Spring事务的传播机制 PROPAGATION_REQUIRED – 支持当前事务,如果当前没有事务

CalvinXCui的博客 5244

Connection is read-only. Queries leading to data modification are not allowed 问题解决方式两种

Connection is read-only. Queries leading to data modification are not allowed 问题解决方式两种

qq_41840735的博客 7121

@Transactional12 种常见失效原因及其解决方案

注解在 Spring 中可能失效的场景较多,以下是。

停住了过去,却停不住时间 881

手把手教你用FreeModbus RTU协议栈实现STM32与PLC通信(附Keil工程)

本文详细介绍了如何使用FreeModbus RTU协议栈在STM32上实现与PLC的工业通信。从环境搭建、工程配置到关键移植接口实现,提供了Keil工程模板和调试技巧,帮助开发者快速掌握Modbus RTU通信技术,适用于工业自动化领域的设备间通信需求。

weixin_42549037的博客 418

Connection is read-only. Queries leading to data modification are not allowe

Connection is read-only. Queries leading to data modification are not allowe 中文意思:连接是只读的。查询导致修改数据不准 我的理解是:你要查询,可能是根据姓名来判断数据库表中是否存在这个人 String sql = "select count(*) from table where name = '

谢彬の优快云专栏 1万+

Clion编译stm32cube初始化工程时non constant or forward reference address expression for section .ARM.extab报错

相信应该有同学在看了稚晖君关于clion开发stm32的文章之后也想在自己PC上实现“优雅の嵌入式开发”遇到和我类似的问题。他的文章是22年写的,我个人猜测应当是版本更新导致的不适配。意思就是说 READONLY 只能在gcc11以后的版本中使用,gcc10及以前的版本将无法正确识别,也就有如下错误。或者就可以将gcc升级至最新的版本。记得在clion工具链中修改c,cpp编译器的位置。可以将文本括号中的 READONLY 全部删除。当时由于没有注意到这行注释导致在这里卡了好久。

2301_77256849的博客 2511

Connection is read-only. Queries leading to data modification are not allowed 解决方法

错误描述 调用save()方法报错 Connection is read-only. Queries leading to data modification are not allowed 产生原因 让所有的方法都加入事务管理,类前面加了注解@Transactional(readOnly = true) 设置为只读的事务,但是增删改就会报错Connection is read-onl...

ladymorgana的博客 4万+

BLE透传速率调优(二)

摘要:本文分析了蓝牙协议中MDbit=1时应连续发送多包但实际只发一包的问题。通过波形分析和代码调试,发现问题的根源在于接收端出现sync error导致提前关闭接收窗口,而非发送端问题。最终通过调整RF时序参数(将rxpathdly改为13us)解决了TX到RX转换的同步问题,使连接事件能正常发送多个数据包,传输速率提升至70kb/s。文中详细记录了使用逻辑分析仪和trace宏调试的过程,揭示了CEVA芯片设计中TX中断与ACK接收的关联特性。

袁赟的博客 799

28、基于图像快速序列视觉呈现(RSVP)的脑机接口特征提取与分类算法综述

本文综述了基于图像快速序列视觉呈现(RSVP)的脑机接口(BCI)中的特征提取与分类算法。RSVP技术通过快速连续呈现图像序列,结合脑电图(EEG)信号分析,实现对目标图像的识别和标记。文章详细介绍了RSVP实验的设计、EEG数据的采集与预处理,并探讨了低信噪比、维度灾难、重叠epoch和不平衡数据集等挑战。针对特征提取,讨论了有监督空间滤波方法(如CSP、xDAWN、LDA波束形成器)的原理和应用。在分类策略部分,涵盖了线性分类技术(如LDA、BLR、LR、SVM)和非线性分类方法(如MLP、CNN)。文

hh234的博客 336

java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed

日志 org.springframework.dao.TransientDataAccessResourceException: ### Error updating database. Cause: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not al...

剑来 1069

从 Claude Code 到 SAP ADT,vibing-steampunk 把 ABAP 开发带进 Agentic 工程现场

vibing-steampunk(vsp)是一个连接SAP ADT API与AI编码代理的桥梁工具,通过MCP协议实现ABAP开发的自动化。它绕开传统GUI脚本方式,直接利用ADT REST API进行代码读写、调试和部署。该工具提供包分析、边界检查、LUW分析等功能,并创新性地采用Hyperfocused模式和方法级编辑来优化token使用效率。通过上下文压缩技术,vsp能智能提取关键代码片段,显著提升AI处理ABAP代码的精准度,为SAP系统现代化改造提供了高效的技术路径。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 190

【spring】@Transactional 注解失效的原因及解决办法

面试中经常会被问到事务失效的场景有哪些,其实在开发中,若是不了解事务失效的场景,当你觉得加了事务,就会回滚,就大错特错了,今天就来了解一下吧。

来到人间不过是个蹭饭的客人,还挑什么酸甜苦辣。 7493

从入门到精通|Yalmip+Cplex在电力系统中的应用(Matlab代码实现)

​ 火电成本包括运行成本、碳捕集成本,其中火电运行成本由运行维护成 本和发电煤耗成本构成,发电煤耗与其出力关系: ,F 为机组煤耗量(kg/h),P 为机组出力/MW;运行维护成本按照 0.5 倍煤耗成本考虑,碳捕集成本取决于碳排放量及碳捕集单价,火电机组相关参数如附表 1 所示,电煤价格为 700 元/t ​

weixin_46039719的博客 1552

DiffusionDriveV2 (1) : 端到端自动驾驶中受强化学习约束的截断扩散建模

DiffusionDriveV2:强化学习约束的截断扩散模型在端到端自动驾驶中的应用 本文针对端到端自动驾驶中扩散模型面临的模式崩溃问题,提出DiffusionDriveV2框架。该方法通过引入强化学习约束,解决了DiffusionDrive依赖模仿学习导致的多样性与持续高质量之间的困境。主要创新包括: 采用尺度自适应乘法噪声促进广泛探索 提出锚点内GRPO管理单个锚点样本间的优势估计 设计锚点间截断GRPO整合全局视角,避免不同驾驶意图间的不当比较 实验表明,该方法在NAVSIM基准测试中达到最先进水平(

@bangbang的博客 381

@Transactional类内部访问失效原因详解

Spring之所以可以对开启@Transactional的方法进行事务管理,是因为Spring为当前类生成了一个代理类,然后在执行相关方法时,会判断这个方法有没有@Transactional注解,如果有的话,则会开启一个事务。 也就是说我们首先调用的是AOP代理对象而不是目标对象,首先执行事务切面,事务切面内部通过TransactionInterceptor环绕增强进行事务的增强,即进入目标方法之前开启事务,退出目标方法时提交/回滚事务。 Spring在扫描bean的时候,如果扫描到方法上有这些注解

Ahuuua的博客 6414

【Linux命令大全】006.网络通讯之netstat命令(实操篇)

本文详细介绍了Linux系统中netstat网络诊断命令的实用技巧。主要内容包括:1) 基本功能与参数详解,展示如何查看网络连接、路由表和接口统计;2) 安装方法及基础用法,如查看TCP/UDP连接、显示进程信息和路由表;3) 高级应用技巧,包括监听端口检查、连接状态统计和实时监控。文章通过表格和代码示例,系统性地呈现了netstat在系统管理中的核心应用场景,是网络故障排查和性能监控的实用指南。

yuhuasheng1997的博客 705

@Transactional注解事务失效的几种原因

@Transactional注解事务失效的几种原因分析,包括解决办法。

技术杠精的博客 1万+

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

@Transactional注解事务失效的七种原因分析

1、异常被捕获后没有抛出 2、抛出非运行时异常 3、方法内部直接调用 4、新开启一个线程 5、非public的方法 6、数据库本身不支持 7、事务传播级别设置错误

自律使我自由 1万+

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

别再踩坑!Spring事务@Transactional失效?一文读懂参数与8大失效场景

在我们开发Spring Boot应用中,很多小伙伴以为只要在方法上加一个 @Transactional,事务就能自动回滚,保证数据一致性。但实际开发中,事务经常出现失效的情况:明明抛了异常,数据库还是提交了。你肯定会疑惑:“为什么我加了注解,数据还是没回滚?” 通过本文博主将彻底和小伙伴们说清楚,让大家别再踩坑!从 @Transactional 的参数详解入手,再结合常见事务失效场景给出 正确写法 vs 错误写法 对比,帮助小伙伴们彻底理解 Spring 事务机制。

Micro麦可乐的博客 4746

为啥@Transactional失效了?

分享一下对Spring@Transactional的理解

u011964735的博客 1761

@Transactional 注解失效的3种原因及解决办法

第一种 l注解标注方法修饰符为非public时,解将会不起作用。例如以下代码。 定义一个错误的@Transactional标注实现,修饰一个默认访问符的方法 在同一个包内,新建调用对象,进行访问。 测试用例 以上的访问方式,导致事务没开启,因此在方法抛出异常时,;操作不会进行回滚。如果方法改为public的话将会正常开启事务,将会进行回滚。在类内部调用调用类内部l标注的方法。这种情况下也会导致事务不开启。示例代码如下。 设置一个内部调用 测试用例。 上面就是使用的测试代码,运行测试知道,外部调用事务方法能够

qq_45228323的博客 1万+

springboot 注解@Transactional失效的原因

springboot 注解@Transactional失效的原因 参考源码分析 https://blog.youkuaiyun.com/oyc619491800/article/details/105826597 一:声明式事务@Transactional 二:注解@Transactional使用 三:常用,使用该注解时,记得加异常回滚, readOnly 属性 readOnly :指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 t

kang1011的博客 1万+

spring动态代理失效,AOP失效,事务@Transactional失效原因

事务基于@Transactional注解和AOP(动态代理)

weixin_42774617的博客 1611
上一篇: Redis的5种数据类型及常用命令
下一篇: Redis两种方式的持久化AoF与RDB解析
Galen-gao
博客等级 码龄9年 931粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值