私は今までトランザクションを意図的に利用する機会が無く、「なんかDBの整合性を保つやつなんだよなー」くらいの理解度でした。他にもログを見ててBEGIN
やCOMMIT
って何...?となっていたこともあり、トランザクション周りについて知る必要があったので、今まで知らなかったことを理解のためにまとめてみます。
トランザクションとは
PostgreSQL 16.4文書には以下のように書かれていました。
トランザクションの基本的要点は複数の手順を単一の「全てか無しか」の操作にまとめ上げることです。 手順の進行途中の状態は他の同時実行中のトランザクションからは見えません。 トランザクションの完結の障害となる何らかのエラーが起こると、それらの手順はどれもデータベースにまったく影響を与えません。
https://www.postgresql.jp/document/16/html/tutorial-transactions.html より
以下が要点だと認識しています。
- DBの変更内容を一括で反映する or 反映しない 仕組み
- 他の同時実行中のトランザクションからは見えない(※実際には設定によって左右される認識)
と言うことで、整合性を保つと言うのは誤りではないものの、より具体的に概念が理解できました。
どうやってトランザクションを実行するのか
PostgreSQLの場合、以下のようにBEGIN
~COMMIT
で囲むことで実行できます。
BEGIN; -- 実行したい処理 COMMIT;
実際にどうなるのか試してみた
ターミナルを2つ準備して試してみます。
以下リポジトリを利用して、dbshell
上でコマンドを実行します。
https://github.com/nibuno/djangoTaskApp
また、トランザクション分離レベルはデフォルトのREAD COMMITTED
で実施しています。
ターミナル1
postgres=# BEGIN; BEGIN postgres=*# INSERT INTO task (title, content, status, "order", created_user_id, limit_date, updated_user_id, created_at, updated_at) VALUES ('Sample Task', 'This is a sample content.', 0, 1, 1, '2024-12-31', 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); INSERT 0 1
ここで、ターミナル2を開いてSample Task
を検索してみます。
ターミナル2
postgres=# select * from task where title = 'Sample Task'; id | content | created_at | updated_at | created_user_id | updated_user_id | title | limit_date | status | order ----+---------+------------+------------+-----------------+-----------------+-------+------------+--------+------- (0 rows)
この段階では、まだ結果が表示されません。
ここでターミナル1でCOMMITしてみます。
postgres=*# COMMIT; COMMIT
その後、改めてターミナル2でSELECT文を実行してみると以下のようになっていました。
postgres=# select * from task where title = 'Sample Task'; id | content | created_at | updated_at | created_user_id | updated_user_id | title | limit_date | status | order ----+---------------------------+-------------------------------+-------------------------------+-----------------+-----------------+-------------+ ------------+--------+------- 37 | This is a sample content. | 2024-11-10 01:33:55.430143+00 | 2024-11-10 01:33:55.430143+00 | 1 | 1 | Sample Task | 2024-12-31 | 0 | 1 (1 row)
という方法で、登録結果が確認できました。