mysql2/mysqljs の affectedRows は既定で『一致行数』(FOUND_ROWS 有効) — 値不変 UPDATE でも 0 にならない
MySQL
Node.js
ORM
データベース
mysql2
知識
判断
Node の mysql2 / mysqljs(mysql) は、接続の capability flags の既定値に CLIENT_FOUND_ROWS を含む。そのため UPDATE の結果 affectedRows は「WHERE に一致した行数(matched/found)」を返し、「実際に値が変わった行数(changed)」ではない。この既定は非自明で、熟練したレビュアでも取り違えやすい。
何を誤りやすいか
- 「行は一致するが SET 値が既存値と同じ UPDATE は affectedRows=0 になる」という MySQL 素の振る舞い(Rows matched:N Changed:0)を前提に、条件付き UPDATE の所有権判定・CAS・存在確認を組むと誤る。FOUND_ROWS が効いていると値不変でも affectedRows は一致行数(=1)になり、判定は正しく通る。(例: 同一秒・同一値で heartbeat を再更新しても所有者なら true になる。)
- 逆に「affectedRows が 0 なら値が変わらなかった」と読むのも誤り。FOUND_ROWS 下での 0 は「WHERE に一致する行が無かった」を意味する。
判断基準
- 「条件付き UPDATE の affectedRows で所有権/CAS/存在を判定する」設計は、driver が FOUND_ROWS 既定(matched) か changed かで意味が反転する。どちらのセマンティクスに依存しているかを意識し、必要なら接続 flags を明示設定する。
- 「値が変わったか」を知りたい場合は affectedRows ではなく changedRows / info の Changed: を見るか、別カラム比較で判定する。
確認方法
- 使用 driver の defaultFlags / 接続 flags に FOUND_ROWS(CLIENT_FOUND_ROWS) が含まれるかを node_modules のソースで確認する(mysql2 は既定で含む)。createPool/createConnection で flags を明示指定すると既定を上書きする点に注意。
- 値不変の UPDATE を1行に対し実行し、affectedRows が 1(matched) か 0(changed) かを実 DB で一度確かめる。