Su的技术博客

  • 首页
  • Java
  • MySQL
  • DDD
  • 事故复盘
  • 架构方案
  • Other
  • 工具
  • 打赏
  • 关于
  1. 首页
  2. Java
  3. 正文
                           

【原创】仅使用set属性值就把数据库数据给改了

2020-04-10 32点热度 0人点赞 0条评论

























1

背景


最近小伙伴要上线一个小特性——审阅状态的变更。在上线的过程中,发现一个非常奇怪的问题。


基本上保证了逻辑没问题 ,多次检查也没问题。但是事实就是发生了!

小伙伴有点怀疑人生了:)。


所以我们临时的处理方式是增加日志打印,逐步验证我们的逻辑。看看我们是如何排查问题的。


使用的技术框架:springboot+jpa



2

问题排查


1)原逻辑代码


ALog aLog = aLogRepository.findOne(logId);
if (aLog.getStatus == UNKNOWN) {
    aLog.setStatus(INIT); // ①
} else {
    // ②
    aLog.setStatus(RUNNING);
    aLogRepository.save(aLog);
    return;
}
// ③发送短信
smsAdapter.sendSms("手机号", "状态变更...");
return true;


上面是经过抽离的主要逻辑,存在的问题:


逻辑不会进入到②,只会进入到①和③,也就是当前的记录状态无需更新,并且需要发送短信。但是数据库的aLog记录状态就被更新了,到底是为什么?又没有调用save方法进行更新记录,怎么就会把数据给改了?


由于多次检查和增加日志逻辑验证,我们最终是确保逻辑是没问题的。


此时,我想到了唯一一个问题,就是跟Hibernate的对象状态有关!那么到底是不是呢,我们就得继续排查确认了。


2)原来是这样的


smsDao.save(sms);
smsHandle.sendSms();


查看了发送短信的逻辑,原来这里会将短信记录保存到数据库,再调用短信接口发送对应的短信内容。


那么,很有可能就是这里的smsDao.save帮忙把aLog顺便一起update了?事实确实如此。小伙伴就把发送短信的逻辑代码注释掉,重新测试调用接口,这时aLog数据库记录就不会被更新了。


所以罪魁祸首就是“它”。


这个时候就确定了是Hibernate包含了三种状态,此时aLog查询出来,数据库有此记录,session也有此对象,说明当前aLog是处于持久化状态,如果在事务提交的时候,会判断当前对象记录是否发生改变,是的话就会触发update操作。


所以,这也就是为什么aLog并没有主动调用save操作,就帮忙把它自动更新了。


重新理了一下逻辑,也调整了下代码,因为①aLog.setStatus(INIT)并不需要,多此一举了。所以把它去掉即可。


3)了解Hibernate的状态


Hibernate存在transient(瞬时状态),persistent(持久化状态)以及detached(离线状态)。


瞬时状态就是刚new出来一个对象,还没有被保存到数据库中,持久化状态就是已经被保存到数据库中,离线状态就是数据库中有,但是session中不存在该对象。


①对于刚创建的一个对象,如果session中和数据库中都不存在该对象,那么该对象就是瞬时对象(Transient)。


②瞬时对象调用save方法,或者离线对象调用update方法可以使该对象变成持久化对象,如果对象是持久化对象时,那么对该对象的任何修改,都会在提交事务时才会与之进行比较,如果不同,则发送一条update语句,否则就不会发送语句。


③离线对象就是,数据库存在该对象,但是该对象又没有被session所托管。



3

总结


虽然这个问题并不难(或者这不算问题),但是为了避免其他人或者你可能以后也会遇到的这种问题,可以很好的帮助(你)避免重蹈覆辙。


1)对于查询出来的对象,如果无需更新就不要set属性值,有时可以创建新变量来存储当前的值;
2)使用JPA(Hibernate)要注意自动会“帮你”更新数据库数据;
3)记录每次遇到的不小不大的问题,可以帮助少踩坑。


参考:
https://www.cnblogs.com/xiaoluo501395377/p/3380270.html
http://www.luyixian.cn/news_show_268613.aspx



推荐好文

1、互联网Code Review最佳实践分享

2、dubbo面试题!会这些,说明你看懂了dubbo源码

3、Kafka面试题!掌握它才说明你真正懂Kafka
4、
Netty 5.0为啥被舍弃?原因竟然是...
5、
中台之上——业务架构系列【汇总】

6、必备瑞士军刀IDEA插件,你使用了哪些

7、线上热更新代码只需3步 Arthas实战

8、Eureka源码剖析之七:架构&面试题【总结】

9、互联网工程师应该用这种姿势打印日志

10、加入:互联网基础/架构交流群

-关注搬运工来架构,与优秀的你一同进步-

如果喜欢这篇文章或支持可以点在看哦↘

本文仅供学习!所有权归属原作者。侵删!文章来源: 搬运工来架构

标签: 原创
最后更新:2020-04-10

Cocodroid

专注Java后端,分享技术。

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

最新 热点 推荐
最新 热点 推荐
殷浩详解DDD 第四讲:领域层设计规范 既生@Resource,何生@Autowired? Go整洁架构实践 接口优化的常见方案实战总结 QQ音乐高可用架构体系 构建一个布隆过滤器 —— Building a Bloom filter
殷浩详解DDD 第四讲:领域层设计规范Redis为什么这么快?构建一个布隆过滤器 —— Building a Bloom filterQQ音乐高可用架构体系接口优化的常见方案实战总结Go整洁架构实践
Chrome插件(扩展)开发全攻略2.6w字,看这篇就够了! Go整洁架构实践 笔记 | Java对象探秘 记一次网络请求连接超时的事故 Eureka源码剖析之一:初始化-启动 定时任务原理方案综述

@Autowired (1) @Resource (1) API网关 (1) ddd (6) DP (1) ElasticSearch (1) eureka (7) go (1) HTTP (1) IDEA (1) iOS (1) Java (8) JSR (1) QQ音乐 (1) repository (1) Spring (1) SQL优化 (1) 代理 (1) 依赖注入 (1) 同城双活 (1) 垃圾回收 (1) 定时任务 (1) 容灾 (1) 布隆过滤器 (1) 异地双活 (1) 接口优化 (1) 故障转移 (1) 数据库 (2) 整洁架构 (1) 文件网关 (1) 方案 (2) 服务续约 (1) 注册中心 (7) 流水账 (1) 流量 (1) 第五 (1) 线上案例 (1) 线上问题 (2) 缓存 (1) 缓存击穿 (1) 编译 (3) 网络 (3) 聊聊 (1) 订单 (1) 设计规范 (1) 详解 (1) 连接池 (1) 限流 (1) 领域驱动设计 (4) 高可用 (1)

COPYRIGHT © 2014-2023 verysu.com . ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

粤ICP备15033072号-2