覆盖Django mysql model中save方法时碰到的一个数据库更新延迟问题
最近有一个需求,通过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方法时碰到的一个数据库更新延迟问题的更多相关文章
- django定义Model中的方法和属性
#定义一个Model class UserProfile(models.Model): user=models.OneToOneField(User,unique=True) phone=models ...
- backbone Model调用save方法的时候提交方式
horizon使用的是backbone框架,但是我们的后台api都是只接收post请求,请求的路径为/api/,根据backbone的官档解释: backbone的model.save方法会判断当前的 ...
- 误删Django的model中的表解决办法
误删Django的model中的表解决办法 1.model里面的表格实际的操作都在migrations文件夹中,里面记录了操作过程,当在database和model中删除表格时要注意初始化数据库时会报 ...
- Django 资源 与 知识 Django中自建脚本并使用Django环境 model中的save()方法说明 filter()用法
Django 资源 与 知识 Django中自建脚本并使用Django环境 model中的save()方法说明 filter()用法 2018/11/06 Chenxin 资料说明 Django基础入 ...
- Django model重写save方法及update踩坑记录
一个非常实用的小方法 试想一下,Django中如果我们想对保存进数据库的数据做校验,有哪些实现的方法? 我们可以在view中去处理,每当view接收请求,就对提交的数据做校验,校验不通过直接返回错误, ...
- CI中的控制器中要用model中的方法,是统一写在构造器方法中,还是在每一个方法中分别写
Q: CI中的控制器中要用model中的方法,是统一写在构造器方法中,还是在每一个方法中分别写 A: 建议统一写,CI框架会自动识别已经加载过的类,所以不用担心重复加载的问题 class C_User ...
- CakePHP采用model的save方法更新数据所需查询
采用model的save方法更新数据所需查询 1. 验证时候要确认是update 或者 create,以便使用对应规则 public $validate = array( 'field_name' = ...
- 使用List中remove方法时需要注意的问题
String str1 = new String("1"); String str2 = new String("2"); String str3 = new ...
- SQL把表中的数据复制到另一个数据库中
1 删除整张表的数据,并还原自增长值TRUNCATE TABLE TbWeixinActivity 2 3张表左连接select a.ID,c.Name,b.nickname,a.CreateDate ...
随机推荐
- Appfuse搭建过程(下源代码不须要maven,lib直接就在项目里(否则痛苦死!))
什么是Appfuse:AppFuse是一个集成了众多当前最流行开源框架与工具(包含Hibernate.ibatis.Struts.Spring.DBUnit.Maven.Log4J.Struts Me ...
- TTransport 概述
TTransport TTransport主要作用是定义了IO读写操作以及本地缓存的操作,下面来看TIOStreamTransport是如何实现的. public abstract class TTr ...
- ps基础练习
1. 直接把图片拖进来 2. F 键 视窗全屏快捷键 3. 此时的图片是“背景”层,不能直接编辑,双击该背景层,就变成了“图层”,就可以编辑了 4. 5. 6. 7. 魔棒工具,在需要去掉的点一下, ...
- leetcode231 2的幂 leetcode342 4的幂 leetcode326 3的幂
1.2的幂 正确写法: class Solution { public: bool isPowerOfTwo(int n) { ) return false; )) == ; } }; 错误写法1: ...
- 容器适配器(一):queue
除了标准的顺序容器外,STL还提供了3种容器适配器,queue,priority_queue和stack 适配器是对顺序容器的包装,它的作用是简化接口. queue接口十分的简单,只有8个方法.再加上 ...
- nginx下配置多个web服务
参考 nginx配置详解 nginx反向代理与负载均衡详解 一.nginx简介: Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能 ...
- Spring(一)之概括与架构
个人说明: 下面有一部分引用该链接:https://www.tutorialspoint.com/spring/spring_architecture.htm 另外一部分加上我个人的使用经验和体会 之 ...
- ajax传递数组,后台接收为null解决方法
traditional:true,加上这个就好,默认为false,即允许深度序列化参数,但是servlet api不支持,所有设为true阻止就好了. $.ajax({ type:'post', ur ...
- uva 10369 Arctic Network (最小生成树加丁点变形)
The Department of National Defence(DND)wishestoconnectseveral northern outposts by a wireless networ ...
- git删除本地保存的账号和密码
使用git在本地拉过一次代码时候git会自动将用户名密码保存到本地. 导致想用别的用户名和密码拉代码时没有权限,这时需要删除或者修改git在本地保存的账户名和密码. 具体办法如下: 1.控制面板--& ...