1
3

More than 3 years have passed since last update.

DjangoのMultiple Databasesのときのselect_for_updateでエラーが出た

Last updated at Posted at 2021-06-30

DjangoでSQLのSLECT FOR UPDATEをするときはQuerySetのselect_for_update()を利用しますが、これを利用してもエラーが出たので少々調べました。

経緯

select_for_update()はトランザクション内、Djangoのtransaction.atomic()内でしか使えません。
もしトランザクション外でselect_for_update()を使うと

django.db.transaction.TransactionManagementError: select_for_update cannot be used outside of a transaction.

とエラーが起きます。

今回、レプリカDBがあるためMultiple Databasesの環境でDjangoを使用していましたが、このMultiple Databasesの環境のトランザクション内でselect_for_update()を使用したら上記のエラーが起きました。
transaction.atomic()のコンテキスト内なのになぜ?となり、少々このあたりのコードを読みました。

結論

Multiple Databasesの環境かつトランザクションを開始するDBがdefaultではないときはtransaction.atomicの引数usingを指定しましょう。例えばhogeDBに保存されたモデルHigeを更新するなら、

with transaction.atomic(using="hoge"):
    hoge = Hige.objects.select_for_update().get(pk=1)

のような感じです。

なぜエラーが起きたのか

Djangoではsettings.pyのDATABASESに追加することでDBを複数利用できますが、色々なところでdefaultのDBが選択されます。今回もそのケースです。
transaction.atomic()はusingでDBを指定しない場合、defaultDBに対してトランザクションを開始します。そして、defaultではない他のDBに保存されているモデルに対してselect_for_update()を使用したため、トランザクション外でのselect_for_update()となりエラーが起きてしまいました。

考えてみると当然で、何も指定せずtransaction.atomic()を使ってもどのDBでトランザクションを開始すればいいかDjango側では判断ができないですよね。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3