遇到了这个问题并找到了两个确定的解决方案后,我认为值得再次提出答案。
这是MySQL默认事务模式的问题。Django从一开始就打开一个事务,这意味着默认情况下您不会看到数据库中所做的更改。
这样演示
在终端1中运行django shell
>>> MyModel.objects.get(id=1).my_field
u'old'
还有另一个在2号航站楼
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> a = MyModel.objects.get(id=1)
>>> a.my_field = "NEW"
>>> a.save()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>>
回到终端1演示问题-我们仍然从数据库中读取旧值。
>>> MyModel.objects.get(id=1).my_field
u'old'
现在在1号航站楼中演示解决方案
>>> from django.db import transaction
>>>
>>> @transaction.commit_manually
... def flush_transaction():
... transaction.commit()
...
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> flush_transaction()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>>
现在读取新数据
这是带有docstring的易于粘贴的代码块
from django.db import transaction
@transaction.commit_manually
def flush_transaction():
"""
Flush the current transaction so we don't read stale data
Use in long running processes to make sure fresh data is read from
the database. This is a problem with MySQL and the default
transaction mode. You can fix it by setting
"transaction-isolation = READ-COMMITTED" in my.cnf or by calling
this function at the appropriate moment
"""
transaction.commit()
替代解决方案是更改MySQL的my.cnf以更改默认事务模式
transaction-isolation = READ-COMMITTED
请注意,这对于Mysql是一个相对较新的功能,会对二进制日志记录/从属产生一些影响。如果需要,您也可以将其放在django连接序言中。
3年后更新
现在,Django 1.6已在MySQL中启用自动提交,这不再是问题。flush_transaction()
无论您的MySQL是处于REPEATABLE-READ
(默认)READ-COMMITTED
模式还是事务隔离模式,上面的示例现在都可以正常运行而无需编写代码。
在非自动提交模式下运行的Django早期版本中发生的事情是,第一条select
语句打开了一个事务。由于MySQL的默认模式是REPEATABLE-READ
这意味着后续select
语句不会读取数据库的任何更新-因此需要flush_transaction()
上面的代码来停止事务并开始新的事务。
仍然有您为什么要使用READ-COMMITTED
事务隔离的原因。如果要在终端1中进行事务处理,并且想要查看来自终端2的写入,则将需要使用READ-COMMITTED
。
该flush_transaction()
代码现在在Django 1.6中会产生弃用警告,因此建议您将其删除。