序文:#
今回は、データベーストランザクションに関連する知識を紹介します。なぜデータベースを今回の紹介の主役に選んだのでしょうか?
データベースは現代のネットワークの重要な構成要素です。情報爆発のビッグデータ時代において、データの急激な増加により、あらゆる業界がますます繁栄しています。大量で多様かつ高速に生成されるデータは、前例のない価値を生み出しています。データは私たちの生活を変え、未来を創造しています。そのため、私たちはますます柔軟で強力なデータベースを必要としています。データの保存と処理をサポートするために。時代の進歩に伴い、データベース操作に関連する技術をマスターすることは、ICT 業界の関係者にとって必須の選択肢となっています。
基本概念#
トランザクションに入る前に、基本的な概念をざっと理解しましょう。これらは今後の学習で使用されます。
- データベースとは何ですか?
"データベース" は、特定の方法で一緒に格納され、複数のユーザーで共有でき、冗長性を最小限に抑え、アプリケーションと独立しているデータの集合です。
- データベース管理システムとは何ですか?
データベース管理システム(Data Base Management System、DBMS)は、ユーザーアプリケーションとオペレーティングシステムの間に位置するデータ管理ソフトウェアであり、データベースシステムの中核です。ユーザーやアプリケーションにデータベースへのアクセス方法を提供します:データベースの作成、クエリ、更新、およびさまざまなデータ制御。
データベース管理システムは、単一のユーザーがデータをクエリや変更するだけでなく、複数のユーザーをサポートすることもできます。複数のユーザーが同時に操作すると、競合が発生し、混雑が発生します。
- ロックとは何ですか?
ロックは、データベースサーバーがデータリソースの並行使用を制御するためのメカニズムです。ロックされたオブジェクトは、ユーザー操作を保持することができ、ロックが解放されるまで他のユーザーはロックを保持する機会を持つことはできません。
ほとんどのデータベースは、次の 2 つのロック戦略を使用します:
- 書き込み操作には書き込みロックが必要であり、読み取り操作には読み取りロックが必要です。テーブルごとに 1 つの書き込みロックのみを割り当て、書き込みロックが解放されるまで読み取り要求を拒否します。
- 書き込み操作には書き込みロックが必要であり、読み取り操作にはロックは必要ありません。
一般的なデータベースでは、異なるストレージエンジンによって異なるロック戦略を選択できます。たとえば、MySQL には InnoDB、MyISAM、MEMORY などの 3 つのストレージエンジンがあります。
- ロックの粒度とは何ですか?
ロックの範囲を指します。データベースでは、サーバーは 3 つの異なるレベルでロックを適用できます。
テーブルロック
同じテーブルのデータを複数のユーザーが同時に変更することを防ぎます。
ページロック
特定のテーブルのページを変更する複数のユーザーを同時に防ぎます。
行ロック
特定のテーブルの特定の行を変更する複数のユーザーを同時に防ぎます。
- ストレージエンジンとは何ですか?
データベースのストレージエンジンは、データベースの基礎となるソフトウェア組織であり、データベース管理システム(DBMS)がデータの作成、クエリ、更新、削除を行うために使用します。異なるストレージエンジンは、異なるストレージメカニズム、ロックレベルなどの機能を提供します。
ロックの動作はストレージエンジンによって決定され、不適切な使用方法によってデッドロックが発生する可能性があります。
たとえば、MySQL には InnoDB、MyISAM、MEMORY などの 3 つのストレージエンジンがあります。
トランザクションとは何ですか?#
シナリオから始めましょう。銀行での送金業務を行う人物を想像してみてください。彼は 1 万元を別の人物に送金する必要があります。通常、送金プロセスはほぼ即座に完了しますが、プロセスを分解すると、送金手順は 3 つに分かれます:1. アカウント残高が 1 万元以上かどうかを確認する、2. 元のアカウントから 1 万元を差し引く、3. 相手のアカウントに 1 万元を追加する。私たちは気づくでしょう、実際にはどのステップでもずれが生じる可能性があり、取り返しのつかない大きな損失を引き起こす可能性があります。したがって、銀行内の金額が損失しないようにするために、次のようにすることができます:この 1 万元を一時的にキャッシュし、相手のアカウントから引き落とし操作が完了したことを確認した後、この 1 万元を相手のアカウントに追加します。そうでなければ、すべての操作は無効になり、元のアカウントからの引き落としもキャンセルされ、相手のアカウントには数が増えません。このような操作をトランザクションロールバックと呼びます。送金操作はトランザクションです。
トランザクションの特性#
世の中は常にさまざまな予期せぬ出来事で満ちていますが、多くは私たちが制御できないものです。たとえば、サーバーの故障、突然の停電、システムのクラッシュなどです。トランザクションが存在しない場合、データベース操作の信頼性は保証されません。ただし、これらの前提条件は、トランザクション自体が信頼性を確保するための十分な基準を持っている必要があります。したがって、先達たちはトランザクションに ACID の 4 つの主要な特性を指定しました。ACID テストに厳密に合格しない限り、トランザクションは機能しません。
-
原子性
トランザクションは、分割することができない最小の作業単位と見なされます。トランザクション内のすべての操作は、すべてが成功するかすべてが失敗するかのいずれかです。トランザクションの一部を実行することは不可能です。
-
一貫性
データベースは常に一貫性のある状態から別の一貫性のある状態に移行します。トランザクションはデータベースの整合性とビジネスロジックの一貫性を破壊することはできません。たとえば、送金が成功した場合でも失敗した場合でも、1 万元が増えたり減ったりすることはありません。
-
分離性
トランザクションの変更は通常、他のトランザクションには見えません。トランザクションは他のトランザクションの実行結果に影響を与えるべきではありません。
-
永続性
トランザクションがコミットされると、その変更は元に戻すことはできません。
トランザクションの ACID 特性は、データベース操作の安全性と信頼性を保証しますが、実際の操作は常に想像しているよりも簡単ではありません。また、トランザクションを追加するには、データベースシステムにさらなる追加作業が必要です。これにより、データベースシステムのパフォーマンスに一定の要件が課せられます。
分離レベル#
実際には、トランザクションが完全に分離されることを保証することは非常に困難です。完全な分離を実現するには、データベースで同時に 1 つのトランザクションのみを実行できるようにする必要がありますが、これによりパフォーマンスが大幅に低下します。現実的には、複数のトランザクションが同時に実行されることがよくあります。
分離性が保証されない場合、データベースの読み書きは次のような状況に直面します。
- ダーティリード:トランザクションがまだコミットされていないデータを読み取ります。たとえば、トランザクション A がトランザクション B の更新データを読み取りますが、トランザクション B がロールバックされたため、A が読み取ったデータは不正確です。
- ノンリピータブルリード:トランザクション A が同じデータを 2 回読み取りますが、その間にトランザクション B がそのデータを変更してコミットしたため、トランザクション A の 2 回の読み取り結果が一致しません。
- ファントムリード:トランザクション A がテーブル全体のデータを変更し、まだコミットされていない間にトランザクション B がテーブルにデータを挿入または削除したため、トランザクション A が変更する必要のあるデータが一致しません。
これに対し、SQL 標準では 4 つの分離レベルが指定されています。
-
未コミット読み取り(READ UNCOMMITTED)
トランザクションはコミットされていないデータを読み取ることができます。分離制御は行われません。
-
コミット読み取り(READ COMMITTED)
未コミットの読み取りは許可されません。トランザクションが開始される前に、すでにコミットされたトランザクションの変更のみが「見える」ようになります。これはほとんどのデータベースのデフォルトの分離レベルです(MySQL を除く)。
-
可再現読み取り(REPEATED READ)
同じトランザクション内で同じレコードを複数回読み取った場合、結果は一貫性がある必要があります。一般的な方法は、トランザクション内で条件に一致するレコードに排他ロックをかけることです。これにより、他のトランザクションはトランザクションが操作するデータを変更できなくなります。これは MySQL のデフォルトの分離レベルです。
-
直列化(SERIALIZABLE)
最も高い分離レベルであり、トランザクションを直列に実行することで実現されます。各行データの読み取りにロックをかけるため、他のトランザクションはデータを変更できません(追加、削除、変更)。ただし、このレベルでは大量のロックのタイムアウトがパフォーマンスに大きな影響を与えるため、注意が必要です。
分離レベル | ダーティリード | ノンリピータブルリード | ファントムリード |
---|---|---|---|
未コミット読み取り(READ UNCOMMITTED) | あり | あり | あり |
コミット読み取り(READ COMMITTED) | なし | あり | あり |
可再現読み取り(REPEATED READ) | なし | なし | あり |
直列化(SERIALIZABLE) | なし | なし | なし |
ブロッキングとデッドロック#
並行性について話すと、ブロッキングの概念についてざっと触れましょう。
複数のトランザクションが同じリソースをロックする場合、ロックが割り当てられていないトランザクションはロックの解放を待たなければなりません。これにより、ブロッキングが発生します。
ブロッキング時間が永久になると、デッドロックが発生します。
トランザクションが同じリソースを相互に占有し、お互いの占有リソースをロックするよう要求すると、デッドロックが発生します。
解決策のアイデア
- ロックのタイムアウト時間が経過した場合、リクエストを放棄します。
- より低い分離レベルを使用して、ロックの保持時間を短くし、ロック競合を減らします。
- トランザクション中のユーザーインタラクションを避け、オブジェクトに順番にアクセスします。
- …….
異なるストレージエンジンは、異なるデッドロック検出およびデッドロックタイムアウトメカニズムを実装しているため、デッドロックの解決策を検討する際には、データベースのストレージエンジンの実装方法とトランザクションログを適切に管理して、問題が発生した場合に効果的なトラブルシューティングと効率的な解決を行う必要があります。
トランザクションのブロッキングとデッドロックの発生は、複数のプロセスの並行性の必然的な結果です。さらに並行性とロックに関する詳細な知識を学びたい場合は、関連する知識を自分で学習することをお勧めします。
まとめ#
この記事では、データベーストランザクションの基礎を紹介しました。以下の内容を初めて学びました:
- データベースとは何か、ロックとトランザクションとは何か
- トランザクションの 4 つの特性:原子性、分離性、一貫性、永続性
- データベースの読み書きにおけるダーティリード、ファントムリード、ノンリピータブルリードの状況
- トランザクションの分離レベル
- ブロッキングとデッドロックの発生と解決策
記事の長さの制約があるため、ここでは基本的な内容のみを紹介しました。データベースは広範で複雑な学問であり、興味がある場合は、自分で深く学習することをお勧めします。筆者の知識は限られているため、記事の内容に誤りがある可能性があるため、読者の皆様のご指摘をお待ちしております。
知識リンク#
データベース学習「SQL 学習ガイド」、「高性能 MYSQL」