Open2

mysql ロストアップデート

syysyy

ロストアップデート = 他のトランザクションが行った更新を消してしまう更新のこと。(あとから行ったトランザクションの結果がDBに保存されるので前のトランザクションの更新結果が消される)

例えばアクセスするたびにカウントアップするテーブルがあったとして、
ちゃんと排他処理しないとトランザクションAとBが同時にカウントアップすると、+2されるのではなく+1になってしまう。

mysql> select * from c;
+---------+
| counter |
+---------+
|       0 |
+---------+
1 row in set (0.00 sec)

A

mysql> select *from c;
+---------+
| counter |
+---------+
|       0 |
+---------+
1 row in set (0.00 sec)

## counter = 0だったから1にする。同時にBのトランザクションもcounter = 0で取得しているのでcounter = 1にしてしまう
mysql> update c set counter = 1 ;
Query OK, 1 row affected (0.01 sec)

B

mysql> select *from c;
+---------+
| counter |
+---------+
|       0 |
+---------+
1 row in set (0.00 sec)

mysql> update c set counter = 1 ;
Query OK, 1 row affected (0.01 sec)

syysyy

ロストアップデートを起こさないために排他ロックをかける。
自分がロックを取っていれば他のトランザクションは待たされるのでロストアップデートは起きない。

A.

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from c for update;
+---------+
| counter |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)

mysql> update c set counter = 2 ;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

B. BはAがコミットするまで待たされる。

mysql> select * from c for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction