博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
覆盖Django mysql model中save方法时碰到的一个数据库更新延迟问题
阅读量:6403 次
发布时间:2019-06-23

本文共 2765 字,大约阅读时间需要 9 分钟。

最近有一个需求,通过django的admin后台,可以人工配置5张表的数据,这些数据进行一些业务规则处理后会统一成一份数据缓存在一个cache之中供服务端业务访问,因而任何一张表的数据更新(增、删、改),都要需要重新根据规则计算数据结果,并更新cache。

首先想到的方法就是覆盖每个表model子类中的save方法,在其中先调用父类的save方法走原有保存逻辑更新数据到数据库后,之后再单独调用一次cache的更新逻辑,这样每张表的任意数据被用户更新后,都将先触发model的数据库更新、而后执行cache的数据更新,其中Application表model的代码如下所示:

1 class Application(models.Model): 2     name = models.CharField(max_length=128, blank=False, verbose_name=u'应用名') 3     description = models.TextField(blank=False, verbose_name=u'应用描述') 4     status = models.IntegerField(verbose_name=u'状态', choices=APPLICATION_STATUS) 5     mtime = models.DateTimeField(blank=False, verbose_name=u'修改日期', auto_now=True) 6     ctime = models.DateTimeField(blank=False, verbose_name=u'创建日期', auto_now_add=True) 7     class Meta: 8         db_table = 'application' 9         verbose_name_plural = u'应用'10 11     def save(self, *args, **kargs):12         super(Application, self).save(*args, **kargs)13         # 更新memcached逻辑实现函数,该函数为通用函数一部分,会单独建立mysql连接,查询数据库数据,并更新到memcached14         update_memcached_from_mysql()

这样每次在web上新增或者修改数据表记录时,都会先执行父类save操作,save完成后,又会执行update_memcached_from_mysql函数,从mysql查询到最新数据,而后更新到cache之中了。

然而实际测试的时候,发现每次修改数据时,更新到cache的并不是最新数据,而是未修改前的旧数据,比如当前name="test0",修改为name="test1"点击保存后,更新到cache之中的确还是test0,再次修改为name="test2",更新到cache之中的确实test1。

百思不得其解~怀疑是model执行save时,本地有cache会延迟更新,于是在super.save和update_memcached_from_mysql之间增加了time.sleep(10),并多次调用update_memcached_from_mysql函数,可是依然是每次修改保存时,更新到cache的数据都是修改前的取值:

1     def save(self, *args, **kargs):2         super(Application, self).save(*args, **kargs)3         # 更新memcached逻辑实现函数,该函数为通用函数一部分,会单独建立mysql连接,查询数据库数据,并更新到memcached4         update_memcached_from_mysql()5         time.sleep(10)6         update_memcached_from_mysql()7         time.sleep(10)8         update_memcached_from_mysql()

想不出好的解决方案,猜测model真正将数据更新到数据的时机是在save整个函数执行结束后,臆测了如下更新逻辑:

1 子类save执行前2 父类save执行3 更新memcached4 子类save执行结束5 真正更新到数据库

于是必须想办法将第3步的cache更新逻辑挪到save执行结束后,然后要保证每次执行save操作时更新cache,这个位置又不能动~~

于是考虑通过开启独立线程异步执行的方式实现,改写update_memcached_from_mysql,在其中开启独立线程执行一个delay版本的更新函数,线程start后会先休眠n秒钟(n为可控参数,下例中为2),而后才执行从数据库读取数据并更新到cache的逻辑,改完后手动更新数据多次,验证已经能拉取到最新数据。

1 def update_memcached_from_mysql():2     """ 3     猜测由于model的缓存机制,save函数执行完成前,新的数据可能未及时更新到数据库,4     此处开启独立线程执行memcache更新操作,线程中会休眠数秒再从数据库拉取最新数据更新5     """6     td = threading.Thread(target=update_memcached_from_mysql_delay, args=(2, ))7     td.start()

然而之前的更新流程还仅仅是猜测而已,虽然采用线程异步延迟更新cache的方法后,多次修改验证避开了取不到新数据的问题,并不就说明猜测一定是正确的,而且即便猜测是正确的,如果save函数执行完后,model的数据更新没有在线程延迟时间结束前完成,理论上还是会有问题,考虑可以通过设置一个定时任务,比如每隔10分钟定时执行cache更新逻辑,来保证新数据最多延迟10分钟也能生效。

本来想深入探究model save更新机制~然而最近太忙了~~blog都两周没更新了,初步尝试了一下也还没有研究清楚这一块save逻辑的源码,这个数据修改平台也仅供内部使用~~暂时先这么修补一下~~以后有时间再深究这一块的问题~~加入TODO list。

 

转载于:https://www.cnblogs.com/AcAc-t/p/django_model_save_delay.html

你可能感兴趣的文章
ORA-01111: name for data file 119 is unknown - rename to correct file
查看>>
源代码构建Apache反向代理(包括SSL配置)
查看>>
MySQL · 捉虫动态 · 字符集相关变量介绍及binlog中字符集相关缺陷分析
查看>>
.Net Discovery系列之十一-深入理解平台机制与性能影响 (中)
查看>>
在Visual Studio引用对话框中找不到Civil 3D 2011 64位的COM组件的解决办法
查看>>
JS组件系列——自己动手扩展BootstrapTable的 冻结列 功能:彻底解决高度问题
查看>>
用 IIS 搭建 mercurial server
查看>>
git常见操作--忽略文件以及常用命令【转】
查看>>
DotNET企业架构应用实践-数据库表记录的唯一性设计的设计兼议主键设定原则
查看>>
Android -- ListView与ArrayAdapter、SimpleAdapter
查看>>
Oracle数据库中NARCHAR转换成NUMBER类型
查看>>
8月21日云栖精选夜读:Q1财报天猫交易额增速达49%,背后有哪些新技术支撑?...
查看>>
微软:ISO镜像将会是升级Windows 10最可靠最便捷的方式
查看>>
《深入理解OSGi:Equinox原理、应用与最佳实践》一1.2 为什么使用OSGi
查看>>
2015年世界最弱密码公布 123456排第一
查看>>
辽宁移动立足大数据打造新型服务班组
查看>>
构建智慧城市基础设施建设的PPP模式
查看>>
英特尔:勒索软件成黑客惯用伎俩
查看>>
理解Android编译命令
查看>>
Snap业务模式存重大缺陷 无法通过规模经济获益
查看>>