因为 Django ORM update,我今天差点「从删库到跑路」

用户头像
AlwaysBeta
关注
发布于: 2020 年 07 月 13 日
因为 Django ORM update,我今天差点「从删库到跑路」



经过周末两天回血,今天早早来到公司,准备把上周遗留的 BUG 修了,然后再多写几个 BUG。



还没等我把双肩包放好,就看见群里有同事反馈,有一个表的数据没了。



我一看,可不是,原来有几千条,现在就剩十几条了。



大脑迅速转了几圈,相关代码我还真改过,但已经是上上周的事了,初步判定,应该是跟我没关系。但是,身为一名乐于助人的红领巾,我还是要帮忙排查一下的。



事情大概是这样:



我们有一个定时程序,从数据源拉取数据,然后入到一个表里,没有则创建,有则更新。



还有一个定时程序,根据表的 update_time 字段来删除过期数据,过期时间是 7 天。



快速浏览了一下代码,感觉没有什么问题,同事也都表示,最近没动过相关代码。



初步判断,可能是数据源出问题了。



然后手动执行了一下拉取程序,数据源没有问题。



那就奇怪了,难道真是我上上周改的代码出问题了?



心虚使我的后背微微冒汗,怀着忐忑的心情把之前的代码仔细看了一遍。看完后,我眼前浮现出三个字:没问题。



又叫来两个同事一起来帮我 review 一下,三个人对着电脑屏幕,望眼欲穿,频频发出感叹:这没问题啊!



其中一个同事看我用的 update() 方法,说:“是不是数据没变化,update() 就不更新了呢?”



我和另一个同事同声反驳:“不会啊,怎么可能。”



我还补充道:“别这样,要对我们学的知识有自信。”



不过,也实在看不出到底哪里有问题,死马当活马医吧。



我又跑了一遍程序,没想到打脸来的如此之快,update_time 字段还真的没更新。



于是,我改了一点程序,确保入库数据和数据库中的数据是不同的,又跑了一遍。



发现我改的字段更新了,但是唯独 update_time 字段没更新。



然后我把 update() 方法改成 update_or_create() 方法又跑了一遍,因为我上次把 update_or_create() 改成了 update(), update_time 字段更新了。



纳尼?这到底是为啥啊?懵了~



赶紧找谷歌大哥帮帮忙。



一般我们定义 model 中的时间字段是这样的:



create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")



createtime 在第一次新增数据时创建,之后便不再改变,updatetime 会在每次数据更新时更新。



但,update_time 并非每次都更新,比如使用上文提到的 update_or_create() 方法会更新,save() 方法也会更新。因为这两个方法都是走的 Django ORM。



而更适用于批量操作的 update() 方法则是直接执行数据库 SQL,不走 Django ORM,所以 updatetime 也就得不到更新。那要想更新怎么办呢?手动给 updatetime 赋值。



这也太坑了,程序欢天喜地执行了一周都没有问题,没想到隐藏了这么大的一个 BUG,真是学到了。



最后,感谢公司 DBA 大佬帮忙恢复数据,不论原因,过去 7 天,想恢复到哪天的几点就恢复到哪天几点,体验简直不要太好,我想删库跑路都不行了。



技术博客:



https://github.com/yongxinz/tech-blog



同时,也欢迎关注我的微信公众号 AlwaysBeta,更多精彩内容等你来。



发布于: 2020 年 07 月 13 日 阅读数: 40
用户头像

AlwaysBeta

关注

微信公众号:AlwaysBeta 2017.11.30 加入

后端开发,技术栈:Python,Django,Redis,RabbitMQ,Kafka,Elasticsearch,MySQL

评论

发布
暂无评论
因为 Django ORM update,我今天差点「从删库到跑路」