带有自动提交事务的 Django save() 行为

Posted

技术标签:

【中文标题】带有自动提交事务的 Django save() 行为【英文标题】:Django save() behavior with autocommit transactions 【发布时间】:2015-07-24 19:06:24 【问题描述】:

我有以下设置:

几个数据处理工作者通过http从django视图get_conf()获取配置。 使用 mysql / InnoDB 后端将配置存储在 django 模型中 配置模型已覆盖 save() 方法,告诉工作人员重新加载配置

我注意到有时工作人员没有正确收到更改后的配置。特别是,当 conf 重新加载时间比平时短时,工作人员从get_conf() 获得了“旧”配置(缺少最近的更改)。 Django 中使用的事务模型是默认的自动提交。

我想出了以下可能导致该行为的情况:

    新配置已保存 save() 返回但 MySQL / InnoDB 仍在处理(自动)提交 Workers 已启动并为新配置发出 http 请求 MySQL(自动)提交完成

上述场景中的第 2 步是否可行?也就是说,如果正在使用自动提交事务方法,django模型save()可以在数据实际提交到数据库之前返回吗?或者,向下一层,MySQL 自动提交 INSERTUPDATE 操作能否在提交完成之前完成(更新/插入对其他事务可见)?

【问题讨论】:

您的引擎使用的是 InnoDB 还是 MyISAM? InnoDB。该数据库使用默认配置在 Amazon RDS 上运行。有一些大表,但与此问题相关的表很小(大约 128kb 左右) 你能针对这种情况关闭自动提交吗? 你能提供更多关于“告诉工人重新加载”机制的信息吗?如果工作人员处于不同的流程中(例如,如果您通过 Celery 或 Python-RQ 进行通知),那么是的 - 您的第 2 步可以/几乎肯定会发生。 稍微修改一下我的评论:在我熟悉的数据库(PostgreSQL、MSSQL、Oracle)上,任何类型(自动或手动)的提交都会阻塞,直到完成。因此,您描述的流程应该可以工作,因为 db 调用发生在信号之前。如果整个视图都是事务性的(例如,ATOMIC_REQUESTS=True,那么您可能会遇到其他进程在提交发生之前尝试加载的竞争)。考虑到工作人员通过 HTTP 连接获取他们的 conf,是否在任何层都发生了缓存? 【参考方案1】:

对象可能变脏了,请在保存后尝试刷新对象。

obj.save()

obj.refresh_from_db()

参考:https://docs.djangoproject.com/en/1.8/ref/models/instances/#refreshing-objects-from-database

【讨论】:

【参考方案2】:

这绝对看起来像一个竞争条件。

如果只有一个脚本和一个数据库,则永远不会发生您描述的场景。当你 save() 时,该方法在数据实际提交到数据库之前不会返回。

但是,如果您使用的是主/从配置,您可能会成为复制延迟的受害者:如果您在主服务器上写入但在从服务器上读取,那么您的脚本完全有可能不会等待很长时间足以进行复制,并且您在从属服务器有机会复制主服务器之前从它读取旧的 conf。

这样的配置可以使用数据库路由器在 django 中设置,也可以使用数据库代理在数据库端完成。检查一下。

【讨论】:

以上是关于带有自动提交事务的 Django save() 行为的主要内容,如果未能解决你的问题,请参考以下文章

django事务处理

session.save()反映没有事务提交

Django 数据库事务

Django 数据库事务

Django的事务性

Django model.save() 不写入数据库