在Django中,如何实现事务的可重复读取?

时间:2015-06-20 15:31:43

标签: python django transactions isolation-level transaction-isolation

我有一个函数,它在同一个数据集上执行多个查询,我想确保所有查询都能看到完全相同的数据。

就SQL而言,这意味着支持它的数据库的REPEATABLE READ隔离级别。如果数据库没有能力,我不介意更高级别甚至是完全锁定。

据我所知,情况并非如此。即如果我在一个Python shell中运行类似这样的代码:

with transaction.atomic():
    for t in range(0, 60):
        print("{0}: {1}".format(t, MyModel.objects.count()))
        time.sleep(1)

一旦我在另一个中MyModel.objects.create(...),运行循环看到的值立即增加。这正是我想要避免的。进一步的测试显示该行为符合READ COMMITTED级别,这对我的口味来说太宽松了。

我也想强调一点,我希望只针对单个功能实现更严格的隔离级别,而不是整个项目。

实现这一目标的最佳选择是什么?

在我的特殊情况下,我唯一关心的数据库是PostgreSQL 9.3+,但我也希望与SQLite3有一些兼容性,在这种情况下即使完全锁定整个数据库也没关系。然而,显然,解决方案越普遍,它就越受欢迎。

1 个答案:

答案 0 :(得分:9)

你是对的,postgres中的默认事务隔离级别是READ COMMITTED。 您可以在设置中轻松更改它以测试它是否符合您的需求: https://docs.djangoproject.com/en/1.8/ref/databases/#isolation-level

此外,我怀疑你会遇到一些性能问题,因为postgres在处理事务时非常有效。即使在SERIALIZABLE模式下也是如此。此外,mysql具有REPEATABLE READ默认隔离级别,因为我们认为它也不会损害性能。

无论如何,您可以在需要时手动设置隔离模式: http://initd.org/psycopg/docs/extensions.html#isolation-level-constants

要设置自定义事务隔离级别,您可以尝试像:

from django.db import connection

with transaction.atomic():
    cursor = connection.cursor()
    cursor.execute('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ')
    # logic

另外我建议您先在设置中更改默认模式(如果可以)。 然后,如果符合您的需求,您可以将其删除并修改特殊位置的代码。