きり丸の技術日記

技術検証したり、資格等をここに残していきます。

MySQLでセットアップできないマスタデータがあった

始めに

一部の自動テストが書かれていない状況だったため、テストケースを拡充しようとしていました。しかし、テストを書く過程でドハマりした内容があったためブログにします。

環境

  • 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=0id=1としてセットアップされる
  • id=1のレコードもあるため、最終的にid=0でセットアップしたレコードが存在しなくなる

SQLModeの確認方法

次のSQLを実行してください。サーバのデフォルトのSQLMode@@GLOBAL.sql_modeで、現在のセッションのSQLModeSESSION.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を付与するのアプローチはできませんでした。

結局、セットアップする直前でSQLModeNO_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を除外するようにしないといけませんね。