2

パターンを検出できません。おそらく、特定のモデルの 1000 回の編集ごとに 1 回、m2m フィールドで IntegrityError が返されます。ほとんどの場合、このフィールドは変更されませんでした。モデルが保存されると、django は常に m2m フィールドを消去してからアイテムを再追加すると思いますよね? 私はdjangoの呼び出しを見たclear()add()、アイテムを呼び出しました。

私のコードは次のように失敗します:

IntegrityError: 重複したキー値が一意の制約 "app_model_m2m_field_key" に違反しています 詳細: キー (model1_id, model2_id)=(597, 1009) は既に存在します。

アイテムがクリアされる前にアイテムの追加が実行されるように見えますが、これは非常に奇妙です。私はそれを再現しようとしましたが、それは非常に難しく、たまにしか起こりません. 何が原因でしょうか?自動コミットを設定すると、この問題を解決できますか?

前もって感謝します

4

1 に答える 1

3

おそらく、同じような変更を同時にコミットするために 2 つのリクエストが競合している可能性があります。

  1. リクエスト 1 はトランザクションを開始し、既存の M2M 行を削除します。

  2. リクエスト 2 はトランザクションを開始し、同じ where 句で M2M 行を削除します。これは、リクエスト 1 のトランザクションがコミットされるのを待ってブロックします。

  3. リクエスト 1 は、すべての M2M 行を再挿入してコミットします。

  4. 要求 2 が再開され、行を削除せずに削除が成功します。これは、ステートメントの開始時に存在していたすべての行が既に削除されているためです。

  5. リクエスト 2 は M2M 行を再挿入しようとしますが、データベースはそれが既に存在することを検出し、エラーを返します。

これは、(PostgreSQL のデフォルトの READ COMMITTED の代わりに) SERIALIZABLE 分離レベルにアップグレードすることで修正できますが、さらにエキサイティングな潜在的な障害モードとパフォーマンスの低下を犠牲にします。

Django が DELETE の後に一連の INSERT を実行していることは正しいと思いますが、この種の競合を悪化させるため、これはあまり良い計画ではありません。

最良の計画は、実際に変更されたものを特定し、データベースにそれらの変更のみを依頼することです。これは、整合性エラーが発生した場合、実際に競合が発生したためであり、おそらくどうすることもできなかったからです。

于 2012-11-01T21:55:03.227 に答える