背景
社内でデータベース研修が始まったため、いい機会なのでMacにPostgreSQLを入れて遊んでみました。
インストールはここを参照したら簡単でした。
研修はOracleの教科書で進んでいますがまあ基本的な概念は同じですね。
まとめてみると、どういうときにロック取得できないのかが意外と理解できてないことがわかりました。
行ロックの取得(select for update)
Transaction A
nsdb=# begin;
BEGIN
nsdb=# update hello set value = 'ngdesuyo' where num = 3;
UPDATE 1
nsdb=# update hello set value = 'ngdesuyo' where num = 2;
UPDATE 1
Transaction B
begin;
select * from hello where num = 2 for update;
-- ロックしようとしている行の変更がTransaction A でコミットされてないため、ここでwaitになる
Transaction A
nsdb=# commit;
COMMIT
Transaction B
-- select 結果が表示され、行ロックが取得される
num | value
-----+----------
2 | ngdesuyo
(1 row)
再度、行ロックの取得
Transaction A
nsdb=# begin;
BEGIN
nsdb=# update hello set value = 'ngdesutte' where num = 3;
UPDATE 1 -- ロックしてない行のupdate は通る
nsdb=# update hello set value = 'ngdesutte' where num = 2;
-- Transaction B がロックしているためwaitになる
デッドロック
上の状態で、下記のようにするとデッドロックします。
これは簡単な例なのでPostgresサーバが検出してくれました。
Transaction B
nsdb=# select * from hello where num = 3 for update;
ERROR: deadlock detected
DETAIL: Process 2930 waits for ShareLock on transaction 1021; blocked by process 2933.
Process 2933 waits for ShareLock on transaction 1020; blocked by process 2930.
HINT: See server log for query details.
以上になります。