
始めに
一部の自動テストが書かれていない状況だったため、テストケースを拡充しようとしていました。しかし、テストを書く過程でドハマりした内容があったためブログにします。
環境
- MySQL
- 8.0.40
- Python
- 3.13
- SQLAlchemy
- 2.0.40
事象
マスタデータがセットアップできない。id=0のデータがセットアップされない。
詳細
- MySQLの仕様でSQLModeに
NO_AUTO_VALUE_ON_ZEROが無いとAUTOINCREMENT列の 0 は NULL と同じ扱いになり採番される - Upsertでセットアップしていたので、
id=0がid=1としてセットアップされる id=1のレコードもあるため、最終的にid=0でセットアップしたレコードが存在しなくなる
SQLModeの確認方法
次のSQLを実行してください。サーバのデフォルトのSQLModeが@@GLOBAL.sql_modeで、現在のセッションのSQLModeがSESSION.sql_modeです。
サーバのデフォルトは何も設定されていないが、DataGrip等のDBClientが自動でSQLModeを設定することがあるので、確認する際は@@GLOBAL.sql_modeを基本的に確認するようにし、アプリ側でSQLModeを付与する可能性もあるので、念のため両方確認しておくことがベストです。
SELECT @@GLOBAL.sql_mode AS global_sql_mode, @@SESSION.sql_mode AS session_sql_mode;
対策の実装
本番のSQLModeと検証のSQLModeの差分を出すことはできません。そのため、DB本体にSQLModeを付与するのアプローチはできませんでした。
結局、セットアップする直前でSQLModeをNO_AUTO_VALUE_ON_ZEROに変更し、直後に元のSQLModeに戻す対応を取りました。
from sqlalchemy.dialects.mysql import insert # 事前に本番のSQLModeの確認をしてください。Auroraのデフォルトが0なので、0を設定しています await session.execute(text("SET SESSION sql_mode = 'NO_AUTO_VALUE_ON_ZERO'")) stmt = insert(TestMaster).values(dict_value) await session.execute(stmt) await session.execute(text("SET SESSION sql_mode = 0")) await session.commit()
ソースコード
なし
終わりに
DBのテーブルセットアップをRailsで実行しているため、マスタデータなのにidかつAUTOINCREMENTであるのは見逃していました。最初からテストが書かれていれば気づけたのですが…。
悪影響がこのタイミングで出るのは想定外だったので、今後のレビューの際にもマスタデータを作るならidは明示的に作成して、AUTOINCREMENTを除外するようにしないといけませんね。