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

我有以下设置:

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

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

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

  1. 新配置已保存
  2. save() 返回但 MySQL / InnoDB 仍在处理(自动)提交
  3. Workers 已启动并为新配置发出 http 请求
  4. 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,是否在任何层都发生了缓存?

标签: mysql django django-models innodb


【解决方案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 中设置,也可以使用数据库代理在数据库端完成。检查一下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-20
      • 1970-01-01
      • 1970-01-01
      • 2015-09-22
      • 2014-11-25
      • 2020-02-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多