因为 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="更新时间")
create_time 在第一次新增数据时创建,之后便不再改变,update_time 会在每次数据更新时更新。
但,update_time 并非每次都更新,比如使用上文提到的 update_or_create()
方法会更新,save()
方法也会更新。因为这两个方法都是走的 Django ORM。
而更适用于批量操作的 update()
方法则是直接执行数据库 SQL,不走 Django ORM,所以 update_time 也就得不到更新。那要想更新怎么办呢?手动给 update_time 赋值。
这也太坑了,程序欢天喜地执行了一周都没有问题,没想到隐藏了这么大的一个 BUG,真是学到了。
最后,感谢公司 DBA 大佬帮忙恢复数据,不论原因,过去 7 天,想恢复到哪天的几点就恢复到哪天几点,体验简直不要太好,我想删库跑路都不行了。