読者です 読者をやめる 読者になる 読者になる

Carpe Diem

備忘録。https://github.com/jun06t

トランザクションの動作を確認してみる

よくACID特性って聞くけど、Iの独立性ってどうなってるんだろうと思っての動作確認です。

 

◆事前準備

データベースとテーブルを作っておきます。

mysql> create database transaction_test;
mysql> use transaction_test;

mysql> create table user(
    -> id int(10) unsigned not null,
    -> money int(10) unsigned not null,
    -> PRIMARY KEY(id));

データも入れておきましょう。

mysql> insert into user (id, money) values(1, 1000);
mysql> insert into user (id, money) values(2, 2000);
mysql> insert into user (id, money) values(3, 3000);

こんな状態です。

mysql> select * from user;
+----+-------+
| id | money |
+----+-------+
|  1 |  1000 |
|  2 |  2000 |
|  3 |  3000 |
+----+-------+
3 rows in set (0.00 sec)

 

◆やること

やることは複数トランザクションで同じレコードを変更することです。

①開始(A)

②開始(B)

③id: 1を変更(A)

④id: 1を変更(B)

⑤終了(A)

⑥終了(B)

気になるのは③、④の時にどうなるか、ですね。では実験してみましょう。

 

◆実験

①開始(A)

-- ターミナルA
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

②開始(B)

別のトランザクションにするために別ターミナルで実行します。

-- ターミナルB
mysql> use transaction_test;
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

③変更(A)

-- ターミナルA
mysql> update user set money=500 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

④変更(B)

-- ターミナルB
mysql> update user set money=0 where id=1;

するとここで固まります。トランザクションAの方で編集しているので、このレコードにロックがかかっているということですね。

⑤終了(A)

-- ターミナルA
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

このコミットと同時にレコードのロックが外れますので、先ほどのターミナルBを確認してみると

mysql> update user set money=0 where id=1;
Query OK, 1 row affected (4.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

ロックのため4秒という長い時間の処理でしたが、ちゃんと変更されるようになりましたね。 ちなみにずっと放置するとタイムアウトで強制的に処理がキャンセルされます。

⑥終了(B)

この段階でターミナルAで値を確認すると、

-- ターミナルA
mysql> select * from user;
+----+-------+
| id | money |
+----+-------+
|  1 |   500 |
|  2 |  2000 |
|  3 |  3000 |
+----+-------+
3 rows in set (0.00 sec)

まだトランザクションが完了していないのでBの変更は反映されてないです。 ではターミナルBでもコミットします。

-- ターミナルB
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

もう一度ターミナルAを確認してみます。

-- ターミナルA
mysql> select * from user;
+----+-------+
| id | money |
+----+-------+
|  1 |     0 |
|  2 |  2000 |
|  3 |  3000 |
+----+-------+
3 rows in set (0.00 sec)

値が反映されるようになりました。 この行ロックのおかげで、他のトランザクションの処理による矛盾が生じなくなるのですね。