![](/img/trans.png)
[英]How to do a bulk insert or increment type operation with the Django ORM
[英]Django: how to wrap a bulk update/insert operation in transaction?
這是我的用例:
所以基本上我使用的是一個非常方便的功能insert_or_update_many :
但這引入了並發問題。 例如:如果在步驟1中不存在對象,則將其添加到要插入的對象列表中。 但是在此期間可能發生了另一個Celery任務創建了該對象,並且當它嘗試執行批量插入時(步驟3),我收到重復Entry的錯誤。
我想我需要將這3個步驟包裝在“阻止”塊中。 我已經閱讀了有關事務的內容,並嘗試with transaction.commit_on_success:
塊將步驟1,2,3包裝到with transaction.commit_on_success:
with transaction.commit_on_success():
cursor.execute(sql, parameters)
existing = set(cursor.fetchall())
if not skip_update:
# Find the objects that need to be updated
update_objects = [o for (o, k) in object_keys if k in existing]
_update_many(model, update_objects, keys=keys, using=using)
# Find the objects that need to be inserted.
insert_objects = [o for (o, k) in object_keys if k not in existing]
# Filter out any duplicates in the insertion
filtered_objects = _filter_objects(con, insert_objects, key_fields)
_insert_many(model, filtered_objects, using=using)
但這對我不起作用。 我不確定我是否對交易有充分的了解。 我基本上需要一個塊,可以在其中放置幾個操作,以確保沒有其他進程或線程正在訪問(寫入)我的數據庫資源。
我基本上需要一個塊,可以在其中放置幾個操作,以確保沒有其他進程或線程正在訪問(寫入)我的數據庫資源。
Django交易通常不會為您保證。 如果您來自計算機科學的其他領域,那么您自然會以這種方式將事務視為阻塞,但是在數據庫世界中,鎖的級別不同, 隔離級別也不同,並且每個數據庫的鎖也不同。 因此,要確保您的事務能夠做到這一點,您將必須了解事務,鎖及其性能特征,以及數據庫提供的用於控制它們的機制。
但是,讓一堆進程都試圖鎖定表以執行競爭插入並不是一個好主意。 如果很少發生沖突,則可以執行某種形式的樂觀鎖定,如果失敗則重試事務。 或者,您可以將所有這些celery任務定向到一個進程中(如果您無論如何都要獲取表鎖,則並行執行此操作都沒有性能優勢)。
我的建議是從忘記批量操作開始,並使用Django的update_or_create
一次只執行一行。 只要您的數據庫具有防止重復條目的約束(聽起來確實如此),那么它就不會出現上述競爭條件。 如果性能確實不可接受,那么可以考慮使用更復雜的選項。
采用開放式並發方法意味着您不必像通過獲取表鎖那樣防止沖突,而是可以正常進行,然后在發現問題時重試該操作。 在您的情況下,它可能類似於:
while True:
try:
with transaction.atomic():
# do your bulk insert / update operation
except IntegrityError:
pass
else:
break
因此,如果遇到競爭狀況,則產生的IntegrityError
將導致transaction.atomic()
塊回滾已進行的所有更改, while
循環將強制重試該事務(現在大容量操作現在可能會進行重試)查看新存在的行,並將其標記為要更新而不是插入)。
如果沖突很少發生,則這種方法非常有效,如果沖突頻繁發生,則非常糟糕。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.