7

我有一個函數,在同一個數據集上執行多個查詢,我想確保所有查詢都能看到完全相同的數據。在Django中,如何實現交易的可重複讀取?

在SQL而言,這意味着爲支持它的數據庫重複讀隔離級別。如果數據庫不可用,我不介意有更高的級別,甚至完全鎖定。

據我看到的,這是情況並非如此。即如果我在一個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的一些兼容性在這種情況下甚至完全鎖定整個數據庫是跟我沒關係。然而,顯然,解決方案越一般,越優選。

+0

緩存這個元數據是一種可接受的方法? –

+0

不幸的是,沒有。我所做的查詢計算了原始事件數據的各種統計數據,並且具有一致的視圖,我將不得不將整個數據集拉到內存中,這是我真正不想做的事情。 – drdaeman

回答

6

你說的沒錯,在Postgres的默認事務隔離級別讀取已提交。 您可以輕鬆地更改設置來測試它是否適合你的需求: 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 

此外,我建議你更改缺省首先設置模式(如果可以的話)。 然後,如果將符合您的需求,您可以刪除它,並在特殊的地方修改代碼。

+0

感謝您的回覆。我之前遇到過性能問題(我認爲這是大約五年前),將默認隔離級別從SERIALIZABLE更改爲READ COMMITTED(這是非Django項目)對性能有合理的影響。也許這只是我的特殊情況,或者我遇到了一些錯誤。無論哪種方式,我都不願意在全局範圍內設置過於嚴格的隔離級別,並且真的想知道是否有一種方法可以在執行單個函數或代碼塊期間進行更改。或者要知道這是不可行的,因爲ORM設計中的某些東西阻止了這一點。 – drdaeman

+0

當然,有些情況下嚴格的隔離模式是矯枉過正的。無論如何,postgres將盡其所能:)爲代碼的特定部分設置一些非默認的隔離級別絕對沒問題。在整個項目中使用同一個項目更加一致,因爲它確保您至少不會忘記在某個地方完成任務。用代碼示例更新了答案。 – alTus

+1

問題是你必須在任何查詢之前調用'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ',並且在Django中做起來並不簡單 –