「まえがき」の記事の内容は、大まかにMySQLのトランザクション管理についてです。
「属性列」MySQL
「ホームページリンク」個人ホームページ
《作者》 メイプルリーフ氏(fy)
目次
1. 事業コンセプト
トランザクションの概念
DML
MySQL トランザクションは、すべてが正常に実行されるか、すべてが失敗してロールバックされる一連のデータベース操作 (一連のステートメント) を指します。トランザクションの目的は、データベースの一貫性と整合性を確保することです。- トランザクションは実行または実行されるものであり、主に大規模な操作と複雑さの高いデータを処理するために使用されます。
- 電子商取引 Web サイトの注文支払いシナリオを想定します。このシナリオでは、注文の支払いには、注文テーブル、在庫テーブル、支払記録テーブルなどの複数のデータ テーブルに対する複数のステップと操作が含まれます。
- たとえば、ユーザーが支払いボタンをクリックするとトランザクションが開始され、注文の作成、在庫の差し引き、支払い記録の作成という操作が順番に実行されます。これらの操作のいずれかが失敗した場合、トランザクション全体がロールバックされ、注文は作成されず、在庫は差し引かれず、支払い記録も作成されません。すべての操作が正常に実行された場合にのみ、トランザクションが送信され、注文の支払いが完了します。
- このように、複数の MySQL ステートメントが必要となり、これらすべての操作が組み合わされて 1 つのトランザクションを形成します。
- DML をもう一度思い出してください。
DML【data manipulation language】
データ操作言語。データを操作するために使用される命令を表しますinsert,delete、update
。DML は、命令を表す別のDQL
データ クエリ言語に分割されます。select
MySQL では同時に多数のトランザクションが発生する場合があり、これらのトランザクションを制御しないと実行時に問題が発生する可能性があります。
各トランザクションには少なくとも 1 つまたは複数の SQL が含まれており、全員が同じテーブル データにアクセスすると、保護されていないと必ず問題が発生します。トランザクションは複数のSQL文で構成されているため、実行途中でエラーが発生したり、再実行したくない場合がありますが、すでに実行されている場合はどうすればよいでしょうか。
したがって、完全なトランザクションは単純な SQL セットではなく、次の 4 つの属性も満たす必要があります。
- アトミック性:トランザクション ( )
transaction
内のすべての操作は完全に完了しているか、完了していないかのいずれかであり、中間リンクで終了することはありません。Rollback
トランザクションの実行中にエラーが発生した場合は、トランザクションがまったく実行されなかったかのように、トランザクションが開始される前の状態にロールバック ( ) されます。 - 一貫性: データベースの整合性は、トランザクションの開始前およびトランザクションの終了後に損なわれません。これは、書き込まれるデータが、データの精度や連結など、事前に設定されたすべてのルールに完全に準拠する必要があり、後続のデータベースがスケジュールされた作業を自発的に完了できることを意味します。
- 分離: データベースでは、複数の同時トランザクションが同時にデータの読み取り、書き込み、変更を行うことができます。分離により、複数のトランザクションが同時に実行される場合のクロス実行によるデータの不整合を防ぐことができます。
Read uncommitted
トランザクション分離は、非コミット読み取り ( )、コミット済み読み取り (read committed
)、反復読み取り (repeatable read
)、シリアル化 (Serializable
) などのさまざまなレベルに分かれています。 - 耐久性: トランザクションが完了すると、データへの変更は永続的に保持され、システムに障害が発生した場合でも失われることはありません。
上記の 4 つの属性の略称は次のとおりですACID
。
- 原子性 (
Atomicity
不可分性とも呼ばれる) - 一貫性 (
Consistency
) - 孤立(
Isolation
独立とも呼ばれます) - 永続性(
Durability
)
なぜ物事が起こるのか
- トランザクションは、基本的に、アプリケーションがデータベースにアクセスするときに、トランザクションによってプログラミング モデルが簡素化され、ユーザー自身がさまざまな潜在的なエラーや同時実行の問題を考慮する必要がなくなるように、MySQL ライターによって設計されました。
- MySQL が単にデータ ストレージ サービスを提供するだけの場合、ユーザーはネットワークの異常やサーバーのダウンタイムなど、データベースにアクセスする際のさまざまな潜在的な問題を考慮する必要があります。
- したがって、トランザクションの本質はアプリケーションにサービスを提供することであり、データベース システムに固有のものではありません。データベースを一定期間使用した後、トランザクションが必要であることがわかり、MySQL の作成者はトランザクションをカプセル化してサポートしました。
2. トランザクションバージョンのサポート
MySQL では、Innodb
データベース エンジンを使用するデータベースまたはテーブルのみがトランザクションをサポートしており、トランザクションはMyISAM
サポートされていません。
次のコマンドを使用して MySQL データベース エンジンを表示し、どのエンジンがトランザクションをサポートしているかを確認します。
show engines;
例証します:
Transactions
InnoDB
: ストレージ エンジンがトランザクションをサポートしているかどうかを示します。ストレージ エンジンがトランザクションをサポートしていることがわかりますが、MyISAM ストレージ エンジンはトランザクションをサポートしていません。
3. 取引の提出方法
トランザクションには、自動送信と手動送信という 2 つの一般的な送信方法があります。
トランザクションがどのように送信されたかを表示します。
show variables like 'autocommit';
注記:ON
自動コミットがオンであることを示し、値が はOFF
自動コミットがオフであること、つまりトランザクションの送信方法が手動送信であることを示し、 MySQL の自動コミット モードを変更するために使用
できます。SET
SET AUTOCOMMIT=0; --禁止自动提交
SET AUTOCOMMIT=1; --开启自动提交
注: 0 に設定すると、自動送信がオフになることを意味します。これは、トランザクション送信方法を手動送信に設定するのと同じです。
4. トランザクションの共通操作方法
デモンストレーションを容易にするために、MySQL の分離レベルはuncommitted を読み取るように設定する必要があります。つまり、実験現象の観察を容易にするために、分離レベルは比較的低く設定されています。
分離レベルは次のとおりです (分離レベルは順番に増加し、読み取り非コミット分離レベルが最も低くなります)
- コミットされていない読み取り(
Read uncommitted
) - ReadCommit(
read committed
) - 反復可能な読み取り (
repeatable read
) - シリアライズ(
Serializable
)
最低の分離レベルを設定します。
set global transaction isolation level read uncommitted;
知らせ: グローバル分離レベルを設定した後、現在のセッションの分離レベルは変更されません。影響を受けるのは、その後に新しく確立された MySQL との接続のみです。したがって、セッションの分離レベルが正常に設定されたことを確認するには、ターミナルを再起動する必要があります。
クライアントを再起動した後、再度ログインすると、次の内容が表示されます。
次にテストテーブルを作成します
create table if not exists account(
id int primary key,
name varchar(50) not null default '',
blance decimal(10,2) not null default 0.0
)ENGINE=InnoDB DEFAULT CHARSET=UTF8;
4.1 トランザクションの通常の動作
テスト1
2 つの端末を起動し、それぞれの端末でトランザクションを開始します (右側でトランザクションを開始しなくても問題ありません)。トランザクションを開始するには、次のコマンドのいずれかを使用します。
begin;
-- or
start transaction;
トランザクションの開始後、クエリ テーブルにはデータがありません。
注記: ここでのトランザクションの送信方法は自動送信です。
左側のターミナルのトランザクションは、savepoint
セーブ ポイントを作成するコマンドを使用します。このコマンドは、セーブ ポイントを設定するために使用されます。
savepoint 保存点名字;
左側のターミナルにデータを挿入すると、左側のターミナルのトランザクションによってテーブルに挿入されたレコードを右側のターミナルで表示できます。左側のターミナルのトランザクションはコマンドを使用してセーブ ポイントを作成し、続行し
ますsavepoint
。テーブルにレコードを挿入します。このとき、右側のターミナルに新しく挿入されたレコード(コミットされていない読み取り)も表示されます。コマンドを使用して、
左側のターミナルでトランザクションをロールバックします。rollback
rollback to 保存点; -- 事务回滚到该保存点
rollback; -- 默认回滚到事务的最开始
トランザクションはセーブ ポイント s2 にロールバックされます。この時点で、右側の端末では、テーブル内のデータを表示するときに、挿入されたばかりの 2 番目のレコードが表示されません。左側の端末のトランザクションは、コマンドを直接使用して、レコードの先頭にロールバックし
ますrollback
。トランザクションを実行し、適切な端末がデータをクエリします。それが empty の場合、コマンド
を使用してcommit
トランザクションを送信できます (トランザクションの終了を表します)。トランザクションが送信された後は、ロールバックできません。
知らせ: トランザクションがコミットされると、ロールバックすることはできず、再度rollback
ロールバックすることもできません。
上記はトランザクション操作の通常の状況であり、トランザクションは、MySQL クライアントが突然クラッシュしたり、誤ってシャットダウンしたりするなどの異常な状況に対処するためのものです。
4.2 トランザクション例外の検証
デモ 1 (トランザクションの原子性を反映する)
目的:トランザクションが完了していないことを証明するためcommit
、クライアントがクラッシュし、MySQL が自動的にロールバックします (分離レベルは非コミットを読み取るように設定され、トランザクション送信メソッドは自動的に送信されます)。
両方の端末がそれぞれトランザクションを開始し、あらかじめテーブルにデータが入っています(右側でトランザクションが開始されていなくても大丈夫です) 左側の端末のトランザクションでテーブルにレコードを挿入します
。レベルはコミットされていない状態で読み取られるため、右側のターミナルでクエリできます 挿入されたレコードの場合、
左側のクライアントはctrl + \
(トランザクションをコミットせずに)異常
終了します その結果、MySQL はトランザクションを自動的に先頭にロールバックし、以前の状態に戻します挿入されたレコードは右の端末に表示されなくなります。
デモ 2 (トランザクションの永続性を反映)
目的:トランザクションを証明するためcommit
、クライアントがクラッシュしても MySQL データは影響を受けず、データは永続化 (ディスクに保存) されています(分離レベルはまだコミットされていない読み取りに設定されており、トランザクションのコミット方法は自動です)専念)
両方の端末がそれぞれトランザクションを開始します (右側はトランザクションを開始せず、
左側の端末のトランザクションはテーブルにレコードを挿入します。分離レベルはコミットされずに読み取られるため、挿入されたレコードは右側の端末でクエリできます
。端末はトランザクションを送信し、異常終了します
。トランザクションが
コミットされた後もデータは保持されるため、以前に挿入されたレコードは右端末で引き続き表示されますcommit
。以下の実験 3 を使用して検証します。
デモ3(検証実験)
目的:操作により送信方法が自動的に変更され、MySQL が自動的に送信するかどうかの影響を受けないことを証明します。begin
自動送信をオフにする
set autocommit = 0;
左側のターミナルでトランザクションを開始し、テーブルに新しいレコードを挿入します (右側でトランザクションを開始することもできます)。分離レベルはコミットされずに読み取られるため、右側のターミナルで新しく挿入されたレコードをクエリできます。 commits
thetransaction , and then exit異常終了します。トランザクションがコミットされた後もデータは保持されるため、以前に挿入されたレコードは右のターミナルに引き続き表示されます。
上記の説明begin
:または· コマンドを使用して開始されたトランザクションは、設定されているかどうかに関係なく、データが永続化される前にコマンドを使用して手動で送信するstart transaction
必要があります。commit
autocommit
デモ4
目的:単一の SQL ステートメントとトランザクションの間の関係を証明するため
左右の端末で自動送信をオフにし、右側はオフのままにしておきます(右側は動作に影響しません)
set autocommit = 0;
トランザクションを開始せずに、データを直接削除します。分離レベルはコミットされていない状態で読み取られるため、右側の端末でも結果を確認できます。単一の SQL ステートメントを実行した後、左側のクライアントは直接異常終了します。一方、削除されたデータは
、右側の端末のデータはロールバックされます I'm back.
左側の端末は自動送信がONになっていますが、右側の端末は動作に影響はありません。
set autocommit = 1;
トランザクションを開始せずに、データを直接削除します。分離レベルはコミットされていない状態で読み取られるため、右側の端末でも結果が表示されます。単一の SQL ステートメントを実行した後、左側のクライアントは直接異常終了し、データは削除され
ます右側の端末は変更されていません、つまり、左側の端末です 操作はロールバックされませんでした
実験結果は次のことを示しています: 実際、以前は単一の SQL トランザクションを使用していましたが、autocommit
デフォルトでオンになっているため、単一の SQLトランザクションは実行後に自動的に送信されます。
- グローバル変数が
autocommit
設定されているかどうかは単一の SQL ステートメントに影響し、InnoDB
各 SQL ステートメントはデフォルトでトランザクションにカプセル化されます。 autocommit
の場合、ON
単一の SQL ステートメントは実行後に自動的に送信されます。 の場合、OFF
SQL ステートメントの実行後にcommit
手動での送信が必要です。手動で送信されない場合、実行された SQL はロールバックされます。
上記の実験結果
begin
またはを入力している限りstart transaction
、 が設定されているかどうかに関係なく、トランザクションはcommit
永続化される前に送信される必要がありますset autocommit
。- トランザクションは手動でロールバックできますが、動作が異常な場合には MySQL が自動的にロールバックします。
- 各SQL ステートメントはデフォルトでトランザクションにカプセル化され、自動的に送信されます (後述するように、
InnoDB
MySQL には特別な状況があるため、select には特別な状況があります)MVCC
- 上記の実験は、トランザクション自体のアトミック性 (
rollback
) と耐久性 (commit
)を反映しています。
トランザクション操作に関する注意事項
- セーブポイントが設定されていない場合は、トランザクションの先頭までロールバックすることもできます。直接使用します
rollback
(トランザクションがまだコミットされていない場合) - トランザクションがコミットされた場合 (
commit
)、ロールバックすることはできません (rollback
) - トランザクションは、どのセーブポイントにロールバックするかを選択できます (トランザクションがまだコミットされていない場合)。
InnoDB
トランザクションをサポートする、MyISAM
トランザクションをサポートしない
5. トランザクション分離レベル
- MySQL サービスには、複数のクライアント プロセス (スレッド) が同時にアクセスすることができ、アクセスはトランザクション方式で実行されます。
- トランザクションは複数の SQL ステートメントで構成される場合があります。つまり、トランザクションには実行前、実行中、実行後の 3 つの段階があります。
- いわゆるアトミック性とは、ユーザー層からは実行前も実行後も見ることができ、実行中に問題があればいつでもロールバックできるため、ユーザーにとってのシングルトランザクションの特徴がアトミック性です。
- しかし、結局のところ、各トランザクションには実行プロセスがあります。複数のトランザクションが独自の複数の SQL を実行すると、相互に影響を与える可能性があります。たとえば、複数のトランザクションが同じテーブルに同時にアクセスしたり、テーブル内の同じテーブルにアクセスしたりする場合もあります。レコード
- トランザクション実行中にデータベースが可能な限り中断されないようにするために、分離が表示されます。
- トランザクションの実行中にデータベースがさまざまな程度に干渉されることを許可するために、分離レベルが登場しました。
分離レベル: (順に増加)
- Read Uncommitted (
Read Uncommitted
): この分離レベルでは、すべてのトランザクションはコミットされていない他のトランザクションの実行結果を確認できます(実際の運用環境でこの分離レベルを使用することは不可能です)。ただし、これは分離なしと同等であり、ダーティ読み取り、ファントム読み取り、反復不能読み取りなど、多くの同時実行の問題があります。実験の便宜のためにこの分離を使用しました。 - Read Committed (
Read Committed
): この分離レベルは、ほとんどのデータベースのデフォルトの分離レベルです (MySQL のデフォルトではありません
)。これは、分離の単純な定義を満たします。トランザクションは、コミットされた他のトランザクションによって行われた変更のみを参照できます。この分離レベルでは、反復不可能な読み取りが発生します。つまり、トランザクションの実行時に、トランザクションが複数回選択されると、異なる結果が得られる可能性があります。 - 反復読み取り(
Repeatable Read
): これは MySQL のデフォルトの分離レベルです。実行中に操作データを複数回読み取るときに、同じトランザクションで同じデータ行が表示されることが保証されますが、ファントム読み取りの問題が発生します。 - シリアル化(
Serializable
): これはトランザクションの最高の分離レベルであり、トランザクションが互いに競合しないように強制的に順序付けすることでファントム読み取りの問題を解決します。各読み取りデータ行に共有ロックを追加しますが、タイムアウトやロックの競合が発生する可能性があります (この分離レベルは極端すぎるため、実際の運用環境ではほとんど使用されません)。
分離レベルは基本的にロックによって実装されますが、分離レベルが異なれば、ロックの使用方法も異なります。一般的には、テーブル ロック、行ロック、読み取りロック、書き込みロック、ギャップ ロック ( GAP
)、Next-Key
ロック (GAP+行ロック) などです。
5.1 分離の表示と設定
グローバルコンパートメントレベルの表示
select @@global.tx_isolation;
現在のセッション分離レベルを表示する
select @@session.tx_isolation;
次のコマンドを使用して、現在のセッションの分離レベルを表示することもできます。
select @@tx_isolation;
現在のセッション分離レベルを設定する
set session transaction isolation level 隔离级别;
たとえば、現在のセッションのシリアル化を設定するには
set session transaction isolation level serializable;
注記: 現在のセッションの分離レベルの設定は、現在のセッションにのみ影響します。新しいセッションでは引き続きグローバル分離レベルが使用されます。
グローバル分離レベルを設定する
set global transaction isolation level 隔离级别;
たとえば、グローバル反復読み取りの設定
知らせ: グローバル分離レベルの設定は、後続の新しいセッションに影響しますが、現在のセッションには影響しません。グローバル分離レベルを有効にする必要がある場合は、クライアントを再起動する必要があります。以下は、4 つの分離を示す実験的なデモンストレーションです
。レベル。
5.2 コミットされていない読み取り
2 つの端末を起動し、分離レベルを非コミットを読み取るように設定して、テーブル内のデータを表示します。
set session transaction isolation level read uncommitted;
左右の端末はそれぞれトランザクションを開始し、左側の端末はテーブル内のデータを変更します。左側の端末のトランザクションは送信されず、右側の端末のトランザクションは変更されたデータを参照できます。
説明する:
- このように、トランザクションの実行中に、
commit
実行中の別のトランザクションの更新されたデータ (または他の操作) は読み取られますが、更新されていないデータは読み取られます。この現象はダーティ リーディング (dirty read
)と呼ばれます。 - Read uncommitted はトランザクションの最も低い分離レベルであり、ロックはほとんどなく、効率的ではありますが、多くの問題があるため、使用することはあまりお勧めできません。
5.3 コミットされた読み取り
2 つの端末を起動し、分離レベルを読み取りコミットに設定し、テーブル内のデータを表示します。2 つの
端末はそれぞれトランザクションを開始し、左側の端末がテーブル内のデータを変更します。左側の端末のトランザクションが開始される前は、コミットされた後、右側の端末のトランザクションは表示されません 別のトランザクションにデータを変更した結果
左側の端末のトランザクションがコミットされた後でのみ、右側の端末のトランザクションは変更されたデータを参照できるようになります
説明する:
commit
このように、現在のトランザクションとのトランザクションが2つの期間コミットされておらず、別のトランザクションがこの2つの期間で異なる値を読み取る現象をNon-Repeatable Read()と呼びますnon reapeatable read
。- トランザクションが異なる時点で異なるデータ値を読み取り、誤った計算結果や論理エラーが発生する可能性があるため、この現象はデータの一貫性の問題につながる可能性があります。この分離レベルは推奨されません。
5.4 反復可能な読み取り
2 つの端末を起動し、分離レベルを反復読み取りに設定し、テーブル内のデータを表示します。2 つの端末はそれぞれトランザクションを開始します。左側の端末のトランザクションによって行われた変更は
、右側の端末のトランザクションが開始されるまでは表示されません
。送信されました。左側の端末のトランザクションがコミットされた後でも、右側の端末のトランザクションは変更されたデータを参照できません。右側の端末のトランザクションがトランザクションをコミットしてから
、テーブル内のデータを参照できるようになります。テーブルが見えます。
説明する:
- 上記のように、Repeatable Readと呼ばれます
- ただし、一般的なデータベースが反復読み取り可能な状況では、
update
データは反復読み取りを満たしますが、insert
データをロックすることで分離されており、新規に挿入されたデータは元々存在しないため、ファントムリードの問題が発生します。一般的なロックではそのような問題を防ぐことはできません - しかし、MySQL は、繰り返し読み取り分離レベルでファントム読み取りの問題を解決します (ファントム読み取り問題を解決するための
Next-Key
ロック ( + 行ロック) を通じて)。GAP
- ファントム読み取り: トランザクションの実行中に、同じ選択ステートメントのクエリが、あたかも錯覚があるかのように異なるデータを取得します (新しいデータが表示されます)。この現象はファントム読み取りと呼ばれます。
以下は、MySQL の反復可能な読み取りにファントム読み取りの問題がないことを示しています。
2 つの端末を起動し、分離レベルを反復読み取りに設定し、テーブル内のデータを表示します。その後、
2 つの端末のそれぞれがトランザクションを開始します。左側の端末はテーブルに新しいデータを挿入し、トランザクションを送信します。右側のトランザクションは、端子がまだ見えない 新規挿入データ(ファントム読み取り問題がないことの証明)
5.5 シリアル化可能
2 つの端末を起動し、分離レベルをシリアル化に設定し、テーブル内のデータを表示します。その後、
2 つの端末のそれぞれがトランザクションを開始します。両方のトランザクションがテーブルに対して読み取り操作を実行する場合、2 つのトランザクションは同時に実行できます。ブロックされません。2
つのトランザクションのうちの 1 つがテーブルに書き込みたい場合、このトランザクションは直ちにブロックされます。
右側の端末トランザクションが送信されるまで、左側の端末トランザクションはテーブルを変更できます。
説明する:
- すべての操作はロックされシリアル化されているため問題ありませんが、シリアル化されている限り効率は非常に低く、ほとんど使用されません。
5.6 分離レベルの概要
- このうち、分離レベルが厳しいほどセキュリティは高くなりますが、データベースの同時実行パフォーマンスは低下するため、多くの場合、両者のバランスを取る必要があります。
- mysql のデフォルトの分離レベルは反復読み取りであり、通常は変更しないでください。
分離レベルは次のように要約されます。
6. 一貫性
トランザクションの実行の結果は、データベースをある整合性状態から別の整合性状態に変更する必要があります。
正常にコミットされたトランザクションの結果のみがデータベースに含まれている場合、データベースは一貫した状態にあります。
- トランザクションの実行中にエラーが発生した場合は、トランザクションがまったく実行されなかったかのように、トランザクションを自動的にトランザクションの初期状態にロールバックする必要があります。つまり、一貫性を確保するにはアトミック性が必要です。
- トランザクションの完了後、データへの変更は永続的である必要があり、システムに障害が発生した場合でも失われることはありません。つまり、一貫性には耐久性が必要です。
- 複数のトランザクションが同時に同じデータにアクセスする場合、複数のトランザクションが同時に実行されるときに、クロス実行によってデータの不整合が発生しないことを保証する必要があります。つまり、一貫性を確保するには分離が必要です。
- 実際、一貫性はユーザーのビジネス ロジックと強く関係しています。通常、MySQL は技術サポートを提供しますが、一貫性は依然としてユーザーのビジネス ロジックによってサポートされる必要があります。言い換えれば、一貫性はユーザーによって決定されます。
- 技術的には、一貫性を維持するには、原子性、耐久性、分離性が必要です。
- - - - - - - - - - - 終わり - - - - - - - - - - -
「 作者 」 枫叶先生
「 更新 」 2023.9.7
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
或有谬误或不准确之处,敬请读者批评指正。