您的位置:首页 > 房产 > 建筑 > 电商软件app开发_游戏网页设计模板图片_互联网营销师证书怎么考_东莞seo报价

电商软件app开发_游戏网页设计模板图片_互联网营销师证书怎么考_东莞seo报价

2024/12/24 20:37:26 来源:https://blog.csdn.net/qq_41623592/article/details/142800179  浏览:    关键词:电商软件app开发_游戏网页设计模板图片_互联网营销师证书怎么考_东莞seo报价
电商软件app开发_游戏网页设计模板图片_互联网营销师证书怎么考_东莞seo报价

IDEA调试模式下,单步执行某修改方法后,数据库内容没有更新,同时也无法手动修改对应数据

IDEA、调试模式、单步执行、springboot、mybatis、mapper、MySQL、事务、锁

本想记下完整的技术栈原因,奈何涉及的东西有点多,管不了那么多了,只能先把现象先记录下来,假定一下原因,深层原因只能等有机会的时候再写了。

一定要戒除完美主义,对就算出事故但影响范围也不会很大不很重要的东西,万不可追求0失误,成本太高。

背景

  • 技术框架:springboot、mybatis、MySQL5.6、idea2023
  • 业务场景:不好细说,对业务系统中的一条信息做一项操作,操作的结果是改变这条信息的若干状态。此次调试的目的是观察代码运行时数据库的改变(大概吧,有点久远记不清了)。

问题描述

以下过程依次执行,但并不是一次调试过程,不是一次性发现了这些现象
  1. 记录有问题的请求数据,用idea打开表,筛选到目标数据。
  2. IDEA调试模式运行,在某行修改数据的代码打了一个断点,发请求进入断点。
  3. 鼠标滑动选中 改数据代码,alt+f8打开表达式计算器。
  4. 找到刚才筛选的数据,手动修改一下,发现修改成功。
  5. 在计算器中运行一下修改数据的代码。
  6. 刷新筛选的数据,发现数据没有变化,但是尝试手动修改数据时,发现修改内容无法提交到数据库。
  7. 点击debug窗口的绿色三角继续运行按钮,或按f9,跳过本次调试。
  8. 再次刷新筛选的数据,发现数据更新了。
  9. 手动修改,发现可以修改成功。

分析

估计是MySQL锁在这捣鬼,查来查去东西有点深有点多,先简单记录一下。

反复执行调试过程,不难发现是在执行修改代码后,才会出现各种稀奇的现象。
猜测是为保证事务完整性,修改数据后给数据库加了锁。
而这个锁,由于MySQL的事务隔离级别默认是可重复读
,所以用的是行级锁。
调试时尝试修改别行数据,发现确实可以修改。

但是,如果这里有锁的话,这个锁是加在索引上的,不是在数据上。然而昨天学习了下MVCC,推测这也可能不是锁机制,而是可重复读的快照读搞的鬼。

快照读有一个限制条件,那就是在一个事务中。idea这里数次查询表究竟是不是一个事务不好搜集资料,但可以实验证明锁的存在性:
调试时,在程序修改数据之前,手动筛选数据,然后单步执行让程序修改数据,然后再次筛选查询发现数据无变化。
如果这手动操作都是在一个事务中,第二次查询用的就是快照读,然后,我手动更新一条别行的数据,就能触发当前读,我再一次筛选应该就会看到刚刚程序修改的结果。

如果手动更新后看不到程序修改的结果,这不能说明手动查询不在一个事务,但能说明程序对数据的修改未完全提交到数据库,因而可能有锁的存在。
如果手动更新能看到程序结果,才能说明手动查询是在一个事务中,同时证明此处无锁。

实验结果:

首次实验(失败),
过程不规范,发出请求进入断点后,手动修改了一下数据(因为忘了先把数据改成非目标数据),
然后打开计算器执行代码,手动刷新,数据无变化,单步执行代码,数据无变化,查看日志,发现修改行数为0,f9放行代码,发现响应为失败。手动查询,数据无变化。

再次实验(失败),
手动刷新数据,重发请求进入断点,单步执行,发现数据无变化,放行代码,数据无变化。屏蔽断点,多次请求,数据无变化。检查数据,数据无问题。

这似乎说明手动窗口和一次请求处理都是一个事务?关闭手动查表窗口,重新打开,筛选、搜索,查看数据是上次的数据。
重新请求进入断点(失败),发现数据还是没有变化,没有结果。
突然发现程序运行和手动查询用的不是一个数据库,至此所有实验破产。

发送请求进入断点,手动筛选、修改数据成功,计算器执行修改语句成功1行,手动查询 数据无变化,手动修改目标行对应列数据 提交缓慢、失败,idea提示:

java.sql.SQLException: Lock wait timeout exceeded; try restarting transaction at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040) at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1348) at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025) in RemotePreparedStatementImpl.executeUpdate(RemotePreparedStatementImpl.java:293)

刷新数据放弃修改,目标行数据无变化,
手动修改相邻行对应列数据,无法提交,提示同上,刷新,
手动修改目标行无关列数据,无法提交,提示同上,刷新,
手动修改相邻行无关列数据,无法提交,提示同上,刷新,
手动修改任意行无关列数据,提交成功,重新筛选,目标行数据无变化,无法修改同一筛选条件下的相邻行无关列(刚刚修改成功的列)。
单步执行修改数据代码,成功1行,手动查询数据无变化,
放行代码,手动查询出现目标数据,手动修改目标行成功。

手动修改任意行后查询无结果,再看错误提示,证明确实是加锁了。筛选下相邻行不能修改,说明确实是在索引加锁了,且条件较强。
重新调试,单步修改后,修改任意行对应列数据,提交成功,重新筛选,目标数据无变化,
仅指定其中一个筛选条件(目标行用三个条件定位),任意数据无法修改,
切换筛选条件,发现可以修改,查看表定义,该列无独立索引,
切换筛选条件,无法修改,查看表定义,该列有独立索引。

综上,调试过程中,和目标行相关的所有符合条件的索引,即便是仅满足其中一个条件,也会对该行加锁。

解决方案

其实算不上解决,调试过程中,注意三点:

  • 注意断点前后及调试过程中执行的修改语句,在修改前可手动操作,也可查看到实际数据。
  • 断点运行到修改语句后,或用计算器修改了数据后,不要查看数据库数据,这已经不是运行过程中的实际数据了。
  • 手动点击继续运行按钮或本轮调试完成后,才可以查看到实际运行后的数据结果,方可进行后续操作(修改、后续处理过程)。

声明:本文使用八爪鱼rpa工具从gitee自动搬运本人原创(或摘录,会备注出处)博客,如版式错乱请评论私信,如情况紧急或久未回复请致邮 xkm.0jiejie0@qq.com 并备注原委;引用本人笔记的链接正常情况下均可访问,如打不开请查看该链接末尾的笔记标题(右击链接文本,点击 复制链接地址,在文本编辑工具粘贴查看,也可在搜索框粘贴后直接编辑然后搜索),在本人博客手动搜索该标题即可;如遇任何问题,或有更佳方案,欢迎与我沟通!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com