オラクルデータベースは、たくさんの情報を効率よく管理するために使われる強力なツールです。
このデータベースの中で、非常に重要な役割を果たすのが「トランザクション」です。
トランザクションは、データを安全に操作するための仕組みで、データベースを使う上で欠かせない基本的な機能です。
この記事では、初心者でもわかりやすいように、トランザクションについて説明していきます。
最初に基本的な考え方をおさえ、その後に実際の使い方を見ていきましょう。
以下の記事ともかなり密接につながってくる内容のため、以下もご確認ください。
【初心者向け】Oracle SQLでの表の作成、INSERT、UPDATE、DELETEをマスター
https://oracle-master00000.com/create-table001
1. トランザクションって何?
トランザクションは、簡単に言うと「データベースで行う一連の作業をひとまとめにしたもの」です。
例えば、銀行でお金を送るとき、送金元の口座の残高を減らし、送金先の口座の残高を増やすという2つの作業を行います。
この2つの作業は、どちらも成功するか、どちらも失敗しなければならないものです。
このように、複数の操作が「すべて成功するか、すべて取り消されるか」をまとめて管理するのがトランザクションです。
例:
AさんがBさんに1000円を送金する場合を考えてみましょう。
- Aさんの口座の残高を1000円減らす。
- Bさんの口座の残高を1000円増やす。
この2つの作業が両方成功すれば、トランザクションは完了します。でも、片方だけ成功して片方が失敗してしまうと、データの整合性(正確さ)が崩れてしまいます。だからこそ、トランザクションを使って「両方成功するか、どちらもキャンセルするか」を保証することが重要です。
2. トランザクションの特性(ACID)
トランザクションは、正しく動作するために「ACID特性」と呼ばれる4つのルールに従っています。これらを守ることで、データの安全性や正確さが保たれます。
- A(原子性: Atomicity)
一つのトランザクションは、すべて成功するか、すべて失敗するかのどちらかです。途中でエラーが起きた場合は、それまでの変更はすべてキャンセルされます。 - C(一貫性: Consistency)
トランザクションを行った後でも、データの整合性が保たれるようにします。つまり、データのルールが壊れないように操作されます。 - I(独立性: Isolation)
同時に実行されるトランザクションは、お互いに影響を与えません。例えば、別のユーザーがデータを操作していても、自分の操作が問題なく進むようになっています。 - D(永続性: Durability)
一度トランザクションが成功(コミット)すれば、その変更は失われません。仮にシステムが突然停止しても、その変更はデータベースに確実に保存されています。
3. トランザクションの操作(基本コマンド)
オラクルデータベースでトランザクションを操作するための3つの基本コマンドを覚えておくと便利です。
- COMMIT: 変更を確定して保存する。これでトランザクションが完了します。
- ROLLBACK: トランザクション中の変更を取り消す。やり直したいときに使います。
- SAVEPOINT: トランザクションの途中で一時的に保存して、後でそのポイントまで戻ることができます。
例:
銀行の送金処理を行うときのトランザクションの流れを見てみましょう。
-- トランザクションの開始
UPDATE accounts SET balance = balance - 1000 WHERE account_id = 'A123';
UPDATE accounts SET balance = balance + 1000 WHERE account_id = 'B456';
-- 変更を確定する(コミット)
COMMIT;
上記のSQL文では、まず口座Aの残高を減らし、その後口座Bの残高を増やしています。そして、最後にCOMMIT
を使ってこれらの変更をデータベースに反映させています。
もし何か問題があって送金を取り消したい場合、ROLLBACK
コマンドを使ってやり直しができます。
-- 変更を取り消す(ロールバック)
ROLLBACK;
4. トランザクションの流れ
トランザクションがどのように進むのかを、ステップごとに見ていきましょう。
- トランザクションの開始
最初のデータ操作(INSERT、UPDATE、DELETE)が実行されると、トランザクションが自動的に始まります。 - データの変更
データの追加、更新、削除などの操作が行われますが、まだ他の人からはその変更は見えません。 - コミットまたはロールバック
変更を確定する場合はCOMMIT
を、やり直したい場合はROLLBACK
を使います。 - トランザクションの終了
COMMIT
またはROLLBACK
を使ってトランザクションが完了します。これでトランザクションの一連の作業が終了します。
【実行例 – COMMIT】
SQL> select * from accounts;
ACCOUNT_ID ACCOUNT_NAME BALANCE
ーーーーーーーーー ーーーーーーーーーーー ーーーーーーーーー
A123 Yamada Taro 5000
B456 Suzuki Hanako 3000
C789 Tanaka Jiro 10000
SQL> UPDATE accounts SET balance = balance – 1000 WHERE account_id = ‘A123’; ★トランザクション開始
1行が更新されました。
SQL> UPDATE accounts SET balance = balance + 1000 WHERE account_id = ‘B456’;
1行が更新されました。
SQL> select * from accounts;
ACCOUNT_ID ACCOUNT_NAME BALANCE
ーーーーーーーーー ーーーーーーーーーーー ーーーーーーーーー
A123 Yamada Taro 4000 ★
B456 Suzuki Hanako 4000 ★
C789 Tanaka Jiro 10000
SQL> commit;
コミットが完了しました。 ★トランザクション終了
SQL>
【実行例 – ROLLBACK】
SQL> select * from accounts;
ACCOUNT_ID ACCOUNT_NAME BALANCE
ーーーーーーーーー ーーーーーーーーーーー ーーーーーーーーー
A123 Yamada Taro 5000
B456 Suzuki Hanako 3000
C789 Tanaka Jiro 10000
SQL> UPDATE accounts SET balance = balance – 1000 WHERE account_id = ‘A123’; ★トランザクション開始
1行が更新されました。
SQL> UPDATE accounts SET balance = balance + 1000 WHERE account_id = ‘B456’;
1行が更新されました。
SQL> select * from accounts;
ACCOUNT_ID ACCOUNT_NAME BALANCE
ーーーーーーーーー ーーーーーーーーーーー ーーーーーーーーー
A123 Yamada Taro 4000 ★
B456 Suzuki Hanako 4000 ★
C789 Tanaka Jiro 10000
SQL> rollback;
ロールバックが完了しました。 ★トランザクション終了
SQL> select * from accounts;
ACCOUNT_ID ACCOUNT_NAME BALANCE
ーーーーーーーーー ーーーーーーーーーーー ーーーーーーーーー
A123 Yamada Taro 5000 ★変更が取り消されている
B456 Suzuki Hanako 3000 ★変更が取り消されている
C789 Tanaka Jiro 10000
SQL>
COMMIT、ROLLBACK実行前にSELECT文で変更した内容が正しいか確認しましょう!
もし、SELECT
で確認せずにCOMMIT
をしてしまうと、誤った変更が確定してしまい、後から修正するのが難しくなることがあります。逆に、ROLLBACK
するべき場面でも適切に確認しておけば、不要なデータの巻き戻しを防ぐことができます。
つまり、SELECT
で確認することで、安全で正確なデータ操作ができるようになるのです。
COMMIT、ROLLBACK以外でもトランザクションが終了する場合があります。
1.DDL文の実行(例: CREATE
, ALTER
, DROP
)
オラクルデータベースでは、CREATE TABLE
や ALTER TABLE
、DROP TABLE
などのデータ定義言語(DDL)を実行すると、自動的にトランザクションがコミットされます。これは、DDL文が実行されると、オラクルはその前に行われていたトランザクションを自動的にコミットしてからDDLを実行し、その後さらに自動コミットを行うからです。
2.プログラムの正常終了
PL/SQLのプロシージャやスクリプトの実行が正常に終了した場合、そのトランザクションが自動的にコミットされます。
3.データベースセッションの終了
ユーザーがデータベースセッションを終了(ログアウト)した場合、明示的に COMMIT
または ROLLBACK
されなければ、オラクルは自動的にコミットを行います。
これらの操作がトランザクションを終了させる場合があるので、特にDDL文を使うときには、トランザクションの状態に注意が必要です。
5. トランザクションのベストプラクティス
最後に、トランザクションを使う上で覚えておきたいポイントを紹介します。
- トランザクションは短く保つ
トランザクションが長時間続くと、他のユーザーがデータにアクセスできなくなることがあります。必要な操作をできるだけ早く行い、COMMIT
やROLLBACK
を実行しましょう。 - エラーハンドリングをしっかり行う
トランザクション中にエラーが発生することもあります。エラーが起きた場合は、必ずROLLBACK
で変更を取り消して、安全な状態に戻すようにします。
6.トランザクション実行に関わるロック
オラクルデータベースでは、トランザクションが実行されている間にデータの整合性を保つために「ロック」という仕組みが使われます。ロックは、複数のトランザクションが同時に同じデータにアクセスしたときに、データが不整合になったり、誤った結果が得られるのを防ぐためのメカニズムです。ロックの基本的な仕組みを簡単に説明します。
1. ロックの基本的な仕組み
ロックとは、特定のデータ(行やテーブルなど)が他のトランザクションによって同時に変更されないように「鍵」をかけることです。あるトランザクションがデータを変更しようとしている場合、他のトランザクションがそのデータを同時に変更したり、読んだりすることが制限されます。
オラクルデータベースには、主に2種類のロックがあります。
2. ロックの種類
- 排他ロック(Exclusive Lock)
- 排他ロックは、あるトランザクションがデータを変更しようとしたときにかかるロックです。排他ロックがかかっているデータは、他のトランザクションがそのデータを変更することはできません。通常、
UPDATE
、DELETE
、INSERT
操作を行うと排他ロックがかかります。 - 例: トランザクションAがテーブルの行を更新中の場合、トランザクションBはその行を更新することができません。トランザクションAが
COMMIT
またはROLLBACK
を実行してロックが解除されるまで、トランザクションBはその行に対する変更を待つ必要があります。
- 排他ロックは、あるトランザクションがデータを変更しようとしたときにかかるロックです。排他ロックがかかっているデータは、他のトランザクションがそのデータを変更することはできません。通常、
- 共有ロック(Share Lock)
- 共有ロックは、データを他のトランザクションが読むことはできるが、変更はできない状態を保証するロックです。これは通常、
SELECT ... FOR UPDATE
といったクエリで使用されます。この場合、そのデータは他のトランザクションによって参照(読み取り)は可能ですが、変更はできません。
- 共有ロックは、データを他のトランザクションが読むことはできるが、変更はできない状態を保証するロックです。これは通常、
3. ロックの動作例
例えば、銀行口座の送金処理を考えてみましょう。
- トランザクションA が口座Aから口座Bに1000円を送金しようとします。このとき、トランザクションAは口座Aと口座Bに対して排他ロックをかけます。これにより、他のトランザクションがこの2つの口座に対して変更を加えることができなくなります。
- トランザクションB が同時に口座Bの残高を変更しようとしても、トランザクションAのロックが解除されるまで(
COMMIT
またはROLLBACK
されるまで)待機しなければなりません。
4. ロックの目的
ロックの主な目的は、データの整合性と一貫性を保証することです。具体的には、以下のような状況を防ぐためにロックが重要です。
- データの競合: 複数のトランザクションが同じデータを同時に変更することで、データが矛盾してしまうことを防ぎます。
- 不正な読み取り: あるトランザクションがデータを変更している最中に、他のトランザクションがその未確定のデータを読んでしまうこと(ダーティリード)を防ぎます。
ロックが発生しない場合に起こりうる例。
トランザクション実行時にロックをかけないと以下のような状態が発生する可能性があり、更新しようとしている行にロックをかけることはデータの整合性を保つためにとても重要です。
例:
トランザクションAが口座残高を5000円から3000円に更新しようとしますが、まだコミットしていません。その間に、トランザクションBが同じ口座の残高を参照し、3000円と認識して処理を行います。しかし、トランザクションAがロールバックした場合、実際の残高は変更されていない5000円に戻るため、トランザクションBの処理が不正確なデータに基づいて行われることになります。
5. デッドロック(Deadlock)
ただし、ロックには注意点があります。2つ以上のトランザクションが互いにロックを取り合って進行できなくなる「デッドロック」という状態が発生することがあります。オラクルデータベースはデッドロックを自動的に検出し、デッドロックが発生した場合は、一方のトランザクションをロールバックしてデッドロックを解消します。
まとめ
オラクルデータベースにおけるトランザクションは、データの安全性や整合性を確保するための重要な機能です。初心者でも、基本的な概念とコマンドを理解することで、安全にデータを操作できるようになります。トランザクションのACID特性やコマンドの使い方を覚えて、効率よくデータベースを管理しましょう。
コメント