affected rows

MySQL で UPDATE 文を実行したときに、マッチした行の数と実際に更新処理がされる行の数は一致しない。
ということを知らずにいて一時間ほどさまよってた。
UPDATE 文が作用した行数が 1 以上であれば、すでにテーブルにはレコードがあり、そのレコードが更新されたとしてそこで終了。行数が 1 未満であれば、テーブルにはレコードなかったので、INSERT 文を実行する。
なんてロジックにしていたら、アクセス数が多くなったときに、UPDATE 文が複数のクライアントで同じになってしまい、余分にレコードが INSERT されてしまっていた。面倒くさくても事前に SELECT して、対象のレコードがあるかないか確かめなきゃダメだね(REPLACE は使えない状況だった)。

<?php
// updated がすでに '2010-05-12 00:00:00' になっていると、更新は実行されないので
// affected rows は 0.
$query = "UPDATE hoge SET updated = '2010-05-12 00:00:00' WHERE id = 123";
$affected_rows = $db->exec($query);
if ($affected_rows < 1) {
  // INSERT
} else {
  // NOP
}