はじめに
トランザクションについてメモ
参考
トランザクションとは
- 複数のSQL処理を1つの基本処理単位とする仕組み
- トランザクションに含まれるすべてのSQL処理について、必ず「すべての実行が完了しているか」、「1つも実行されていない」のどちらかの状態にする
- トランザクションに含まれる複数のSQLがDBMSによって不可分なものとして扱われる性質のことをトランザクションの原子性という
原子性確保の仕組み
- トランザクション中のSQLによってテーブルデータが書き換えれると、それは確定ではなく仮の書き換えとして管理される。
- トランザクションが終了する際に仮の書き換えをすべて確定したことにする。この確定行為のことをコミット(commit)という
- トランザクション中に異常が発生して中断した場合、DBMSはそれまで行ったすべての仮の書き換えをキャンセルして、「なかったこと」にすることをロールバック(rollback)という
トランザクションの指定方法
- トランザクションの開始
- BEGIN;
- トランザクションの終了、変更の確定
- COMMIT;
- トランザクションの終了、変更の取り消し
- ROLLABACK;
例えばSpringの@transactionアノテーションでは裏で上記コマンドが発行されているようです
同時アクセスの副作用
- ダーティーリード
- まだコミットされていない(キャンセルされてしまうかもしれない未確定の情報)変更を他の人が読めること
- 反復不能読み取り
- あるテーブルに対してSELECTしたあと、他の人がUPDATEで書き換えて、次にSELECTした際に結果が異なること
- ファントムリード
- 2回のSELECTの間に他の人がINSERTで行を追加するt、2回のSELECT結果行数が変わること
トランザクションの分離
- DBMSはトランザクションを実行する際、他のトランザクションから影響をいけないよう、分離して実行する
- 内部であるトランザクションかが現在読み書きしている行にロックをして、他のトランザクションから読み書きできないようにする
分離レベル | ダーティリード | 反復不可能読み取り | ファントムリード |
---|---|---|---|
READ UNCOMMITTED | あり | あり | あり |
READ COMMITTED | なし | あり | あり |
REPEATABLE READ | なし | なし | あり |
SERIALIZABLE | なし | なし | なし |
多くのDBMSではREAD COMMITED
がデフォルト
ロック
行、テーブル、DBにロックをする
* DBMSによつてはページやひょうスペースがロック対象となる
ロックの種類
- 共有ロック
- 一般的にデータの読み取りを行う際に使用されますが、そのデータが同時に他のトランザクションによって更新されることを防ぐためのロックです。
- 共有ロックは、他のトランザクションが同じデータに対してさらなる共有ロックを取得することを許可しますが、排他ロックの取得はブロックします。
- selectするときに自動で共有ロックされるのかと思ったが、明示的に指定しない限り共有ロックされないみたい
- 排他ロック
- データの変更を行うためのロック。データの変更中に他のトランザクションからの読み取りや変更を防ぐ。
- update、deleteなどは排他ロックがかかる
- 分離レベルによって、排他ロック中に他のトランザクションがアクセスできるかどうか決まるREAD COMMITTEDでは排他ロックがかかっているデータに対する読み取りは、ロックが解除されるまで待機します。ロックが解除されて変更がコミットされた後のデータが読み取られます。
楽観ロック、悲観ロック
共有ロック、排他ロック、楽観ロック、悲観ロックは、データベースや並行プログラミングの文脈で使われる用語で、データへの同時アクセスをコントロールする方法を示しています。これらの概念は関連しているが、それぞれ異なる側面を扱っています。以下にそれぞれの概念を説明します:
-
共有ロック (Shared Lock)
- 複数のトランザクションが同時にデータを読むことができるが、そのデータを変更することはできない。共有ロックがある間、そのデータに対する排他ロックは取得できない。
-
排他ロック (Exclusive Lock)
- 一度このロックが取得されると、他のトランザクションはそのデータを読むことも書き込むこともできない。排他的なアクセス権を持つ。
-
悲観ロック (Pessimistic Locking)
- トランザクションがデータを読み込むとき、他のトランザクションが同時にそのデータを変更することを「期待しない」ため、初めからロックを取得するアプローチ。つまり、最初から最悪のシナリオ(他のトランザクションが干渉する)を想定している。通常、排他ロックや共有ロックのような機構を使って実装される。
-
楽観ロック (Optimistic Locking)
- トランザクション開始時にデータにロックをかけず、コミット時に他のトランザクションがそのデータを変更していないかをチェックするアプローチ。変更があった場合、トランザクションは失敗し、再試行が必要となる。通常、データのバージョン番号やタイムスタンプを使って実装される。
関連性:
-
共有ロックと排他ロックは、通常、悲観ロックの戦略の中で用いられる。データにアクセスしようとする際に、それを他のトランザクションから守るための明示的なロックをかける。
-
楽観ロックは、データの競合を前提とせず、最後のチェック時にのみ競合を確認する。これは高い並行性を持つシステムで有効であることが多い。
それぞれのロック戦略は、使用するシステムやアプリケーションの特性、要件に応じて適切に選択する必要があります。
楽観ロック(Optimistic Locking)のメリット
-
パフォーマンス向上
- 楽観ロックは、データのロックを最小限に抑えるため、データベースのオーバーヘッドが少なくなります。結果として、システム全体のスループットや応答時間が向上する可能性があります。
-
スケーラビリティ
- データベースのロックが最小限であるため、多くのユーザーやトランザクションを同時に処理できるようになります。
-
デッドロックのリスク低減
- 悲観ロックでは、異なる順序で複数のリソースをロックしようとするトランザクション間でデッドロックが発生するリスクがあります。楽観ロックを使用すると、このリスクが軽減されます。
-
ユーザーエクスペリエンスの向上
- ユーザーがデータを長時間編集している間、そのデータが他のユーザーによってロックされることはありません。これにより、ユーザーは自由に作業を進めることができます。
-
短いトランザクション期間
- 楽観ロックは通常、トランザクションの最後のステップでのみロックを行います。このため、トランザクションの期間が短くなり、リソースを長時間保持することなく迅速にリリースすることができます。
注意: 楽観ロックの最大の欠点は、競合が多い環境では、データの競合によってトランザクションが頻繁に失敗する可能性があることです。そのため、楽観ロックと悲観ロックのどちらを使用するかは、アプリケーションの具体的な要件やデータアクセスの特性に応じて慎重に選択する必要があります。