我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

问题

今天项目测试一个方法的时候,发现日志报错

日志报错大致如下: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并不实现各个数据库持久层的事务实现,而是提供对应的事务管理器,如下图所示:


我们首先查看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做演示:

  
  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方法出错时候,整个方法能进行事务的回滚。这样完美,问题解决了.

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

这篇文章主要介绍了Spring接口方法加@Transactional失效的原因解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-03-13

Spring接口方法加@Transactional失效如何解决

这篇文章主要介绍了Spring接口方法加@Transactional失效如何解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Spring接口方法加@Transactional失效如何解决文章都会有所收获,下面
2023-07-05

黏性定位的失效原因及解决方法

粘性定位为什么会失效?原因及解决方法一、引言在前端开发中,粘性定位(sticky position)是一种常见的布局方式。通过设置元素的定位属性为sticky,可以实现在指定的滚动范围内,元素在页面上的位置保持固定不变,直到达到指定的偏移
黏性定位的失效原因及解决方法
2024-01-29

mysql索引失效的原因及解决方法有哪些

MySQL索引失效的原因及解决方法有以下几个方面:1. 索引选择不当:MySQL根据查询的条件和数据分布情况来选择使用哪个索引。如果查询的条件与索引不匹配或者数据分布不均匀,就会导致索引失效。解决方法是优化查询语句,使用合适的索引。2. 索
2023-08-09

MySQL索引失效的原因及解决方法是什么

MySQL索引失效的原因可能有以下几种:1. 数据分布不均匀:如果某个列的数据分布不均匀,索引可能无法有效地过滤掉大部分的数据,导致索引失效。2. 使用了函数或表达式:如果在查询中使用了函数或表达式来处理索引列,索引可能无法被使用。3. 多
2023-10-25

mongodb索引失效的原因及解决方法是什么

索引在MongoDB中失效的原因可以包括以下几点:数据分布不均匀:如果索引字段上的数据分布不均匀,比如某个字段的大部分值都相同,那么索引的效果会大打折扣,因为查询时仍需要扫描大部分的数据。索引过大:如果索引的大小超过了内存可以容纳的范围,那
2023-10-22

阿里云服务器读取端口数据失败:原因及解决方法

简介在使用阿里云服务器时,有时会遇到读取端口数据失败的问题。本文将探讨这个问题的原因,并提供一些解决方法。原因分析1.端口配置错误首先,读取端口数据失败可能是由于端口配置错误引起的。在阿里云服务器上,端口配置需要正确设置才能正常工作。如果端口配置有误,服务器将无法正确读取端口数据。2.网络连接问题其次,读取端口数据失败
阿里云服务器读取端口数据失败:原因及解决方法
2024-01-29

oracle索引失效的原因及解决方法是什么

Oracle索引失效的原因及解决方法如下:1. 数据块不连续:索引失效可能是由于数据块不连续导致的。解决方法是重新组织表或索引,使用ALTER INDEX ... REBUILD语句可以重新组织索引。2. 数据分布不均匀:索引失效可能是由于
2023-08-20

阿里云服务器添加安全端口失败:原因及解决方法

简介在使用阿里云服务器时,有时候会遇到添加安全端口失败的问题。本文将介绍可能导致该问题的原因,并提供一些解决方法。原因分析1.端口冲突当您尝试添加一个新的安全端口时,可能会出现端口冲突的情况。阿里云服务器默认开放了一些常用的安全端口,如SSH(22端口)和HTTP(80端口)。如果您尝试添加一个与这些默认端口冲突的新端
阿里云服务器添加安全端口失败:原因及解决方法
2024-01-30

@ComponentScan在spring中无效的原因分析以及解决方法

这篇文章将为大家详细讲解有关@ComponentScan在spring中无效的原因分析以及解决方法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。@ComponentScan在spring中无
2023-06-25

idea连接mysql失败的原因及解决方法是什么

连接MySQL失败的原因及解决方法有很多种,以下是一些常见的原因和解决方法:1. 错误的主机名或IP地址:检查主机名或IP地址是否正确,在连接字符串中进行修改。2. 错误的用户名或密码:检查用户名和密码是否正确,确保在连接字符串中正确设置用
2023-08-19

Win7 64位系统XP模式失效的原因及解决方法

XP模式现状:Win7系统中的XP虚拟模式是其一大创新js,可以为用户提供XjavascriptP和Win7两种操作体验。php既解决了旧版软件的兼容性问题,又能发挥Win7的新特性。那么,电脑公司Win7 64位系统XP模式为何会失效呢?
2023-06-08

云服务器桌面连接失败的原因及解决方法

1.网络连接问题如果你无法连接到云服务器的桌面,首先要检查网络连接是否正常。可能的原因包括:-本地网络故障:检查你的本地网络连接是否正常,尝试重新启动你的路由器或调整网络设置。-云服务器网络故障:检查云服务器的网络状态,确保它正常运行并且没有任何网络问题。-防火墙设置:检查你的云服务器的防火墙设置,确保允许远程桌面连接
2023-10-27

WinXP远程桌面连接Win8失败的原因及解决方法

身为WinXP系统的老用户,远程桌面这个功能必须懂的,但最近通过远程桌面连接Win8系统的机子时失败了。什么情况呢?这是由于Win8系统远程连接需要网络www.cppcns.com级别身份验证BIsDQ,而这个WinXP此验证默认是关闭的。
2023-06-14

云亚马逊服务器连接失败的原因及解决方法

1.网络问题导致连接失败云亚马逊服务器连接失败可能是由于网络问题引起的。首先,确保你的网络连接正常,可以尝试以下方法来解决问题:检查你的网络连接是否正常,确保你的设备已连接到互联网。重启你的路由器和设备,有时候这样可以解决网络问题。检查你的防火墙设置,确保亚马逊服务器的访问没有被阻止。2.服务器故障导致连接失败亚马逊服务器可能会出现故障,导致连接失败。在这种情况下,你可以尝试以下方法:检查亚马逊的服务...
2023-10-27

阿里云服务器ECS连接失败的原因及解决方法

本文将介绍阿里云服务器ECS连接失败的常见原因,并提供相应的解决方法,帮助用户快速恢复ECS服务器的正常运行。在使用阿里云服务器ECS时,有时候会遇到连接失败的情况。这可能是由于多种原因引起的,包括网络配置错误、防火墙设置不当、操作系统故障等。以下是一些常见的问题和解决方法:网络配置错误:首先,检查您的网络配置是
阿里云服务器ECS连接失败的原因及解决方法
2024-01-19

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录