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

2020-11-27 10:39:51 浏览数 (1)

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

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

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

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

事情大概是这样:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

赶紧找谷歌大哥帮帮忙。

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

代码语言:txt复制
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 天,想恢复到哪天的几点就恢复到哪天几点,体验简直不要太好,我想删库跑路都不行了。

0 人点赞