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

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

 class Application(models.Model):
name = models.CharField(max_length=128, blank=False, verbose_name=u'应用名')
description = models.TextField(blank=False, verbose_name=u'应用描述')
status = models.IntegerField(verbose_name=u'状态', choices=APPLICATION_STATUS)
mtime = models.DateTimeField(blank=False, verbose_name=u'修改日期', auto_now=True)
ctime = models.DateTimeField(blank=False, verbose_name=u'创建日期', auto_now_add=True)
class Meta:
db_table = 'application'
verbose_name_plural = u'应用' def save(self, *args, **kargs):
super(Application, self).save(*args, **kargs)
# 更新memcached逻辑实现函数,该函数为通用函数一部分,会单独建立mysql连接,查询数据库数据,并更新到memcached
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的数据都是修改前的取值:

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

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

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

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

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

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

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

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

覆盖Django mysql model中save方法时碰到的一个数据库更新延迟问题的更多相关文章

  1. django定义Model中的方法和属性

    #定义一个Model class UserProfile(models.Model): user=models.OneToOneField(User,unique=True) phone=models ...

  2. backbone Model调用save方法的时候提交方式

    horizon使用的是backbone框架,但是我们的后台api都是只接收post请求,请求的路径为/api/,根据backbone的官档解释: backbone的model.save方法会判断当前的 ...

  3. 误删Django的model中的表解决办法

    误删Django的model中的表解决办法 1.model里面的表格实际的操作都在migrations文件夹中,里面记录了操作过程,当在database和model中删除表格时要注意初始化数据库时会报 ...

  4. Django 资源 与 知识 Django中自建脚本并使用Django环境 model中的save()方法说明 filter()用法

    Django 资源 与 知识 Django中自建脚本并使用Django环境 model中的save()方法说明 filter()用法 2018/11/06 Chenxin 资料说明 Django基础入 ...

  5. Django model重写save方法及update踩坑记录

    一个非常实用的小方法 试想一下,Django中如果我们想对保存进数据库的数据做校验,有哪些实现的方法? 我们可以在view中去处理,每当view接收请求,就对提交的数据做校验,校验不通过直接返回错误, ...

  6. CI中的控制器中要用model中的方法,是统一写在构造器方法中,还是在每一个方法中分别写

    Q: CI中的控制器中要用model中的方法,是统一写在构造器方法中,还是在每一个方法中分别写 A: 建议统一写,CI框架会自动识别已经加载过的类,所以不用担心重复加载的问题 class C_User ...

  7. CakePHP采用model的save方法更新数据所需查询

    采用model的save方法更新数据所需查询 1. 验证时候要确认是update 或者 create,以便使用对应规则 public $validate = array( 'field_name' = ...

  8. 使用List中remove方法时需要注意的问题

    String str1 = new String("1"); String str2 = new String("2"); String str3 = new ...

  9. SQL把表中的数据复制到另一个数据库中

    1 删除整张表的数据,并还原自增长值TRUNCATE TABLE TbWeixinActivity 2 3张表左连接select a.ID,c.Name,b.nickname,a.CreateDate ...

随机推荐

  1. Python类的继承(进阶5)

    转载请标明出处: http://www.cnblogs.com/why168888/p/6411918.html 本文出自:[Edwin博客园] Python类的继承(进阶5) 1. python中什 ...

  2. SoapUI这么好,舍得不用吗?

    之前尝试去学习哈SoapUI, 安装都报错,直接拖黑不用,对java开发的产品本身不感冒 后来工作上,和老外沟通,发现他们不会用xmlspy,只会SoapUI,心里都想,不学习看来不方便,然后都安装了 ...

  3. Js 中的 this

    Js 中 this 的理解   this 是啥 ? this是 JavaScript 语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用; 随着函数使用场合的不同,this ...

  4. priority_queue详解

    priority_queue是一个安排好的顺序存储的队列,队首是优先级最高的元素. Template<class T , class Container = vector<T> , ...

  5. [LuoguP1352][FJSC]没有上司的舞会

    [LuoguP1352][FJSC]没有上司的舞会(Link) 现在你有一棵树,每一个点有一个点权\(R[i]\),如果选择了\(i\)点,那么\(i\)子树上的所有的点都不能选,现在要求选择若干个点 ...

  6. App测试需要测什么

    App,做为当下最热的手机安装软件,无论是产品本身的设计还是性能,易用性等都是非常受考验.一个app能在用户的手机上使用,并作为一个长期用户是非常不容易的.那么,App的测试中我们到底要测试什么呢? ...

  7. Vue学习—Vue写一个图片轮播组件

    1.先看效果: 熟悉的图片轮播,只要是个网站,百分之90以上会有个图片轮播.我认为使用图片轮播. 第一可以给人以一种美观的感受,而不会显得网站那么呆板, 第二可以增加显示内容,同样的区域可以显示更多内 ...

  8. python2.7下使用logging模块记录日志到终端显示乱码问题解决

    刚才翻了翻2年以前用python2.7写的一个爬虫程序,主要功能就是把各地市知识产权局/专利局网站的专利相关项目.课题通知,定期爬取和分析,辅助企业进行项目申请. 这里要谈的不是爬虫功能的实现,而是今 ...

  9. oracle定时器在项目中的应用

    业务需求: 现在业务人员提出了一个需求: 在项目中的工作流,都要有一个流程编号,此编号有一定的规则: 前四五位是流程的字母缩写,中间是8位的日期,后面五位是流水码,要求流水码每天从00001开始.即: ...

  10. DBA手记(学习) - LOGMNR 简单而强大的工具

    LOGMNR首先执行一个ddl(或dml)操作,以记录重做信息: SYS@ ora11g>conn scott/tigerConnected.SCOTT@ ora11g>alter sys ...