【mysql】-【トランザクション】

データベーストランザクションの概要

トランザクションはデータベースとファイル システムを区別する重要な機能の 1 つです。トランザクションがある場合、データベースは常に実行されます。同時に、トランザクション メカニズムを通じて特定の時点に復元することもできます。トランザクションがデータベースに送信されたことを確認でき、システムのクラッシュによって変更が失われることはありません

ストレージエンジンのサポート

SHOW ENGINESコマンドを使用して、現在 MySQL でサポートされているストレージ エンジンと、それらのストレージ エンジンがトランザクションをサポートしているかどうかを確認します。
ここに画像の説明を挿入します
MySQL では、InnoDB のみがトランザクションをサポートしていることがわかります。

基本的な考え方

トランザクション: データをある状態から別の状態に変換する論理演算単位のセット。
トランザクション処理の原則は、すべてのトランザクションを作業単位として実行し、障害が発生しても実行方法を変更できないことです。トランザクション内で複数の操作が実行される場合、すべてのトランザクションがコミットされて変更が永続的に保存されるか、データベース管理システムがすべての変更を破棄してトランザクション全体が初期状態にロールバックされます。

トランザクションの ACID プロパティ

1. 原子性: 原子性とは、トランザクションが分割できない作業単位であり、すべてが送信されるか、すべてが失敗してロールバックされることを意味します。
2. 一貫性: 一貫性とは、トランザクションの実行前後でデータが 1 から変化することを意味します。法的地位別のものに変える法的地位このステータスは文法的なものではなく意味的なものであり、特定のビジネスに関連しています。

では、法的なデータステータスとは何でしょうか? 満足するあらかじめ決められた制約この国家を法的国家といいます。平たく言えば、この状態はユーザーによって定義されます (現実世界の制約を満たすなど)。この状態が満たされる場合、データは一貫性があります。この状態が満たされない場合、データは一貫性がありません。トランザクション内の操作が失敗した場合、システムは現在実行中のトランザクションを自動的にキャンセルし、トランザクション操作前の状態に戻ります。

3. 分離: トランザクションの分離とは、トランザクションの実行が他のトランザクションによって干渉されないことを意味します。つまり、トランザクション内で使用される操作とデータは、他の同時トランザクションから分離され、互いに干渉することはできません。

隔離が保証できない場合はどうなりますか? アカウント A が 200 元、アカウント B が 0 元だとします。アカウント A はアカウント B に 2 回送金し、それぞれの金額は 50 元で、それぞれ 2 つのトランザクションで実行されます。分離が保証できない場合、次の状況が発生します。

# 案例:转账
UPDATE ACCOUNT SET balance = balance - 10 WHERE id = 1; #此时这条DML操作是一个独立的事务
# 服务器宕机
UPDATE ACCOUNT SET balance = balance + 10 WHERE id = 2; #此时这条DML操作是一个独立的事务


ここに画像の説明を挿入します
これら 2 つの SQL は独立したトランザクションであり、最初の SQL の実行後にサーバーがダウンした場合、アカウントから送金される金額は減りますが、アカウントに送金される金額は変わりません。一度送信されると、データベース内のデータへの変更は永続的なものとなり、その後の他の操作やデータベース障害がその変更に影響を与えることはありません。

永続性は次のような方法で達成されます。トランザクションログ保証する。ログには以下が含まれますやり直しログそしてロールバックログトランザクションを通じてデータを変更するときは、まずデータベースの変更情報を REDO ログに記録し、次にデータベース内の対応する行を変更します。この利点は、データベース システムがクラッシュした場合でも、データベースを再起動した後、データベース システム内で更新されていない REDO ログを見つけて再実行できるため、トランザクションを永続化できることです。

5. まとめ: ACID はトランザクションの 4 つの主要な特性であり、この 4 つの特性のうち、アトミック性が基礎、分離が手段、一貫性が制約、耐久性が目標です。

データベース トランザクションは実際には、アトミック性、分離性、実行性、耐久性を確保する必要がある 1 つ以上のデータベース操作であり、データベース設計者は便宜上トランザクションと呼びます。

取引ステータス

トランザクションは抽象的な概念であり、実際には 1 つ以上のデータベース操作に対応することがわかりました。MySQL では、これらの操作の実行のさまざまな段階に基づいて、トランザクションをいくつかの状態に大まかに分割します。

  1. アクティブ: トランザクションに対応するデータベース操作が実行されているとき、トランザクションはアクティブ状態にあると言います。
  2. 部分的にコミットされた: トランザクション内の最後の操作が完了したが、その操作はメモリ内で実行され、その影響はディスクにフラッシュされないため、トランザクションは部分的にコミットされた状態にあると言います。
  3. 失敗: トランザクションがアクティブまたは部分的にコミットされた状態にある場合、何らかのエラー (データベース自体のエラー、オペレーティング システムのエラー、または直接的な停電など) が発生した可能性があり、実行を続行できないか、現在のトランザクションが停止する可能性があります。トランザクションが実行されるとき、トランザクションは失敗した状態にあるといいます。
  4. 中止: トランザクションの一部が実行されて失敗状態になった場合、トランザクション内で変更された操作をトランザクションが実行される前の状態に復元する必要があります。言い換えれば、失敗したトランザクションが現在のデータベースに与えた影響を元に戻すことです。この元に戻す処理をロールバックと呼びます。ロールバック操作が完了したとき、つまりデータベースがトランザクションが実行される前の状態に復元されたとき、トランザクションは中止された状態にあると言います。
    ここに画像の説明を挿入します

トランザクションの使用方法

トランザクションを使用するには、明示的トランザクションと暗黙的トランザクションの 2 つの方法があります。

明示的なトランザクション

ステップ 1:START TRANSACTIONあるいはBEGIN、トランザクションを明示的に開始することもできます。

mysql> BEGIN;
#或者
mysql> START TRANSACTION;

START TRANSACTIONステートメントの特別な点は、ステートメントBEGINの後にいくつかの修飾子を続けることができることです。

  1. 読み取り専用: 現在のトランザクションを読み取り専用トランザクションつまり、このトランザクションに属するデータベース操作はデータの読み取りのみが可能ですが、データの変更はできません。

読み取り専用トランザクションでは、他のトランザクションによってアクセスできるテーブル内のデータのみを変更できません。一時テーブル (create tmeporary table を使用して作成するテーブル) については、現在のセッションでのみ表示されるため、実際には、読み取りトランザクションでは、一時テーブルを追加、削除、変更、クエリすることもできます。

  1. READ WRITE: 現在のトランザクションが読み取りおよび書き込みトランザクションつまり、このトランザクションに属するデータベース操作は、データの読み取りとデータの変更の両方が可能です。
  2. 一貫したスナップショットを使用: 一貫した読み取りを開始します。
# 开启一个只读事务
start transaction read only

#开启只读事务和一致性读
start transaction read only, WITH CONSISTENT SNAPSHOT

知らせ:

  1. READ ONLY と READ WRITE は、いわゆるトランザクション アクセス モードを設定するために使用されます。つまり、データベース内のデータに読み取り専用でアクセスするか、読み取り/書き込み方式でアクセスするかです。トランザクションのアクセス モードを読み取り専用に設定することはできません。したがって、トランザクション開始後に READ ONLY と READ WRITE を同時に置くことはできません。
  2. トランザクションのアクセス モードを明示的に指定しない場合、トランザクションのアクセス モードは読み取り/書き込みモードになります。

ステップ 2: トランザクション内の一連の操作 (主に DML、DDL を除く)
ステップ 3: トランザクションのコミットまたはトランザクションの中止 (つまり、トランザクションのロールバック)

# 提交事务。当提交事务后,对数据库的修改是永久性的。
mysql> COMMIT;

# 回滚事务。即撤销正在进行的所有没有提交的修改
mysql> ROLLBACK;

# 将事务回滚到某个保存点。
mysql> ROLLBACK TO [SAVEPOINT]

実際、SAVEPOINT に関連する操作は次のとおりです。

# 在事务中创建保存点,方便后续针对保存点进行回滚。一个事务中可以存在多个保存点
SAVEPOINT 保存点名称

# 删除某个保存点
release savepoint 保存点名称

トランザクションには多くの操作が含まれる可能性があります。最後のステップでミスをすると、ロールバックはトランザクションが実行される前にロールバックされます。トランザクション内の特定の位置にロールバックしたい場合は、セーブポイントを使用できます。 。

暗黙的なトランザクション

MySQL にはシステム変数がありますautocommit

mysql> SHOW VARIABLES LIKE 'autocommit';#默认是ON

ここに画像の説明を挿入します
ここに画像の説明を挿入します

UPDATE ACCOUNT SET balance = balance - 10 WHERE id = 1; #此时这条DML操作是一个独立的事务

UPDATE ACCOUNT SET balance = balance + 10 WHERE id = 2; #此时这条DML操作是一个独立的事务,也就是说,执行完这一行代码,会默认有个commit提交

もちろん、この自動送信機能をオフにしたい場合は、次の 2 つの方法のいずれかを使用できます。

  1. トランザクションを開始するには、START TRANSACTION または BEGIN ステートメントを明示的に使用します。このようにして、このトランザクションがコミットまたはロールバックされる前に、自動コミット機能が一時的にオフになります。
#方式1:我们在autocommit为true的情况下,使用start transaction 或begin开启事务,那么DML操作就不会自动提交数据
START TRANSACTION;
UPDATE ACCOUNT SET balance = balance - 10 WHERE id = 1;
UPDATE ACCOUNT SET balance = balance + 10 WHERE id = 2; 
COMMIT; #或rollback;
  1. 次のように、システム変数 autocommit の値を OFF に設定します。
SET autocommit = OFF;# 针对于DML操作是有效的,对DDL操作是无效的。
#或
SET autocommit = 0;

# 设置完成后,执行以下三行代码就是提交一个事务
UPDATE ACCOUNT SET balance = balance - 10 WHERE id = 1;
UPDATE ACCOUNT SET balance = balance + 10 WHERE id = 2; 
COMMIT; #或rollback;

自動コミット機能がオフになっている場合、トランザクションをコミットするコミット ステートメントを明示的に作成するか、トランザクションをロールバックするロールバック ステートメントを明示的に作成するまで、作成する複数のステートメントは同じトランザクションに属します。

Oracle はデフォルトでは自動的にコミットせず、手書きのコミット コマンドが必要ですが、MySQL はデフォルトで自動的にコミットします。

暗黙的にデータを送信する

autocommit キーワードによって制御されない状況
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

トランザクションの使用例

ケースその1

SET autocommit = TRUE; #开启自动提交,默认就已经开启了自动提交,但是我们前面的操作可能把他关了,所以这里再打开一下
#举例1: commit 和 rollback
USE atguigudb2;
#情况1:
CREATE TABLE user3(NAME VARCHAR(15) PRIMARY KEY);

SELECT * FROM user3;

BEGIN;# 当autocommit = TRUE时,使用BEGIN开启事务
INSERT INTO user3 VALUES('张三'); #此时不会自动提交数据
COMMIT;# 提交事务(回滚到这里)

BEGIN; #开启一个新的事务
INSERT INTO user3 VALUES('李四'); #此时不会自动提交数据
INSERT INTO user3 VALUES('李四'); #受主键的影响,不能添加成功
ROLLBACK;# 回滚到最近一个commit那里,此时数据库只有“张三”一条数据

SELECT * FROM user3;

ケース2

#情况2:
TRUNCATE TABLE user3;  # 清空数据
#DDL操作会自动提交数据,不受autocommit变量的影响。
SELECT * FROM user3;

BEGIN;
INSERT INTO user3 VALUES('张三'); #此时不会自动提交数据
COMMIT;

INSERT INTO user3 VALUES('李四');# 默认情况下(即autocommit为true),DML操作也会自动提交数据。(回滚到这里)
INSERT INTO user3 VALUES('李四'); #事务的失败的状态,受主键的影响,不能添加成功

ROLLBACK;# 回滚到上一个commit,事务失败的状态由此变为中止的状态。此时数据库有“张三”、“李四”两条数据

SELECT * FROM user3;

ケース 3

TRUNCATE TABLE user3;

SELECT * FROM user3;

SELECT @@completion_type;# 查询结果:NO_CHAIN,没有链式行为

SET @@completion_type = 1;# 开启链式行为

BEGIN;
INSERT INTO user3 VALUES('张三'); 
COMMIT;

SELECT * FROM user3;# 此时数据库只有“张三”一条数据

INSERT INTO user3 VALUES('李四');
INSERT INTO user3 VALUES('李四'); #受主键的影响,不能添加成功

ROLLBACK;

SELECT * FROM user3;# 此时数据库只有“张三”一条数据

ここに画像の説明を挿入します

ケース 4: INNODB と MyISAM を体験する

CREATE TABLE test1(i INT) ENGINE = INNODB;

CREATE TABLE test2(i INT) ENGINE = MYISAM;

#针对于innodb表
BEGIN# 开启一个事务
INSERT INTO test1 VALUES (1);# 插入一条数据
ROLLBACK;# 回滚

SELECT * FROM test1;# 数据库没有数据


#针对于myisam表:不支持事务
BEGIN# 开启一个事务
INSERT INTO test2 VALUES (1);# 插入一条数据
ROLLBACK;# 回滚

SELECT * FROM test2;# 数据还在,所以myisam不支持事务

ケース 5: 経験値セーブポイント

CREATE TABLE user3(NAME VARCHAR(15),balance DECIMAL(10,2));

BEGIN
INSERT INTO user3(NAME,balance) VALUES('张三',1000);
COMMIT;

SELECT * FROM user3;


BEGIN;
UPDATE user3 SET balance = balance - 100 WHERE NAME = '张三';

UPDATE user3 SET balance = balance - 100 WHERE NAME = '张三';

SAVEPOINT s1;#设置保存点

UPDATE user3 SET balance = balance + 1 WHERE NAME = '张三';

ROLLBACK TO s1; #回滚到保存点


SELECT * FROM user3;

ROLLBACK; #回滚操作

SELECT * FROM user3;

セーブポイントにロールバックすることは、トランザクションの中止状態ではありません。トランザクションに 5 つの操作がある場合、最初の 2 つの操作を実行した後は、問題がないことがわかります。セーブポイントを設定しました。後続の操作が失敗した場合, このセーブポイントにロールバックできます。このセーブポイントにより、最初の 2 つの操作が正しく実行されたことが保証されますが、セーブポイントにロールバックしても、トランザクションが中断された状態ではありません。セーブポイントにロールバックした後は、トランザクションが実行される前にロールバックする必要があります。実行するか、コードを書き続けて操作を実行し、残りの 3 つの操作を実行し、それらが正しいことを確認してからコミットします。

取引の一般的なカテゴリ

トランザクション理論の観点から、トランザクションは次のタイプに分類できます。

  1. フラット トランザクション: 通常は、begin、commit、rollback を使用します。
  2. セーブポイントを使用したフラット トランザクション: セーブポイントを使用したフラット トランザクション
  3. チェーンされたトランザクション: トランザクションは、チェーンされた複数のサブトランザクションで構成されます。
  4. ネストされたトランザクション: トランザクションは複数のサブトランザクションをネストします。
  5. 分散トランザクション
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します

トランザクション分離レベル

MySQL はクライアント/サーバー アーキテクチャ ソフトウェアです。同じサーバーに対して複数のクライアントが接続できます。各クライアントがサーバーに接続した後、それをセッション (セッション) と呼びます。各クライアントは、独自のセッションでサーバーにリクエスト ステートメントを発行できます。リクエスト ステートメントはトランザクションの一部である場合があります。つまり、サーバーは複数のトランザクションを同時に処理する場合があります。トランザクションには分離特性があります。理論的には、トランザクションが特定のデータにアクセスする場合、他のトランザクションはキューに入れられる必要があります。トランザクションが送信された後でのみ、他のトランザクションはデータにアクセスし続けることができます。ただし、これはパフォーマンスに大きな影響を与えます。トランザクションの分離を維持するだけでなく、同じデータにアクセスする複数のトランザクションを処理するときにサーバーのパフォーマンスをできるだけ高くしたいと考えています。二人の間でオフになります。

データの準備

1. テーブルを作成する

CREATE TABLE student (
studentno INT,
name VARCHAR(20),
class varchar(20),
PRIMARY KEY (studentno)
) Engine=InnoDB CHARSET=utf8;

2. データを挿入する

INSERT INTO student VALUES(1, '小谷', '1班');

データの同時実行性の問題

トランザクションの分離と同時実行性の間でどのようにトレードオフを行うのでしょうか? まず、同じデータにアクセスするトランザクションが逐次実行されることが保証されていない場合 (つまり、一方が実行される前に他方が実行されるという保証がない) に発生する可能性がある問題を見てみましょう。

脏写(ダーティ・ライト)

セッション A とセッション B の 2 つのトランザクションの場合、コミットされていない別のトランザクションであるセッション B によって変更されたデータをトランザクション セッション A が変更した場合、それはダーティ ライトが発生したことを意味します。
ここに画像の説明を挿入します

ダーティリード

セッション A とセッション B の 2 つのトランザクションの場合、セッション A はセッション B によって更新されたがまだコミットされていないフィールドを読み取ります。後でセッション B がロールバックされた場合、セッション A によって読み取られたコンテンツは一時的なものとなり、無効になります。
ここに画像の説明を挿入します
セッション A とセッション B はそれぞれトランザクションを開きます。セッション B のトランザクションはまず、学生番号が 1 としてリストされているレコードの名前列を「Zhang San」に更新し、次にセッション A のトランザクションが学生番号が 1 としてリストされているレコードをクエリします。 , カラム名の値が「Zhang San」として読み取られ、セッション B のトランザクションが後でロールバックされた場合、セッション A のトランザクションは存在しないデータを読み取ったことと同じになり、この現象はダーティ リーディングと呼ばれます。

非反復読み取り

セッション A とセッション B の 2 つのトランザクションの場合、セッション A がフィールドを読み取り、次にセッション B がフィールドを更新します。セッション A が同じフィールドを再度読み取ると、値は異なります。これは、反復不可能な読み取りが発生したことを意味します。
ここに画像の説明を挿入します
セッション B でいくつかの暗黙的なトランザクションを送信しました (これは暗黙的なトランザクションであることに注意してください。つまり、トランザクションはステートメントの終了時に送信されます)。これらのトランザクションは、studentno 列が 1 であるレコードの列名の値を変更しました。その後、セッション A のすべてのトランザクションが最新の値を表示できる場合、この現象は非反復読み取りとも呼ばれます。

ファントム

セッション A とセッション B の 2 つのトランザクションでは、セッション A がテーブルからフィールドを読み取り、次にセッション B がテーブルにいくつかの新しい行を挿入します。その後、セッション A が同じテーブルを再度読み取ると、さらにいくつかの行が存在します。つまりファントムリーディングが発生しているということです。
ここに画像の説明を挿入します
セッション A のトランザクションは、まず、条件 Studentno > 0 に基づいてテーブル Student をクエリし、名前列の値が 'Zhang San' のレコードを取得します。次に、暗黙的なトランザクションがセッション B に送信され、テーブル Student にレコードが挿入されます。新しいレコード。その後、セッション A のトランザクションが同じ条件 Studentno > 0 に基づいてテーブル Student をクエリし、結果セットにはセッション B のトランザクションによって新しく挿入されたレコードが含まれます。この現象はファントム読み取りとも呼ばれます。新しく挿入されたレコードをファントム レコードと呼びます。
ここに画像の説明を挿入します

SQL の 4 つの分離レベル

上記では、複数のトランザクションを同時に実行するときに発生する可能性のあるいくつかの問題を紹介しました。これらの問題は優先順位に分類されています。これらの問題を重大度に従ってランク付けします脏写>脏读>不可重复读>幻读パフォーマンスの一部と引き換えに分離の一部を放棄するという私たちの意欲がここに反映されています: いくつかの分離レベルの設定. 分離レベルが低いほど、より多くの同時実行の問題が発生します。SQL 標準では 4 つの分離レベルが確立されています。

  1. READ UNCOMMITTED: Read uncommitted. この分離レベルでは、すべてのトランザクションが他のコミットされていないトランザクションの実行結果を確認できます。ダーティ リード、反復不能リード、ファントム リードは回避できません。(通常は使用しません)
  2. READ COMMITTED: 読み取りがコミットされました。これは分離の単純な定義を満たします。トランザクションは、コミットされたトランザクションによって加えられた変更のみを確認できます。これは、ほとんどのデータベース システム (Oracle など、MySQL のデフォルトではありません) のデフォルトの分離レベルです。ダーティ リードは回避できますが、ノンリピータブル リードとファントム リードの問題は依然として存在します。
  3. REPEATABLE READ: 反復読み取り。トランザクション A がデータを読み取った後、トランザクション B がそのデータを変更してコミットし、その後トランザクション A が再度データを読み取り、元の内容が読み取られます。ダーティ リードとノンリピータブル リードは回避できますが、ファントム リードの問題は依然として存在します。これは MySQL のデフォルトの分離レベルです。(MySQL のデフォルト)
  4. SERIALIZABLE: シリアル化可能で、トランザクションがテーブルから同じ行を確実に読み取ることができます。このトランザクションの実行中、他のトランザクションはテーブルに対して挿入、更新、および削除の操作を実行できません。同時実行の問題はすべて回避できますが、パフォーマンスは非常に低くなります。ダーティ リード、反復不可能なリード、ファントム リードを回避できます。(オラクルのサポート)

SQL 標準では、分離レベルが異なると、同時トランザクションによって重大度の異なる問題が発生する可能性があると規定されており、具体的な状況は次のとおりです
ここに画像の説明を挿入します
ダーティ ライトの問題は非常に深刻であるため、分離レベルに関係なく、ダーティ ライトの発生は許可されません。
分離レベルが異なると現象も異なり、ロックと同時実行メカニズムも異なります。分離レベルが高くなるほど、データベースの同時実行パフォーマンスは低下します。4 つのトランザクション分離レベルと同時実行パフォーマンスの関係は次のとおりです。
ここに画像の説明を挿入します

MySQL でサポートされる 4 つの分離レベル

ここに画像の説明を挿入します
ここに画像の説明を挿入します

トランザクションの分離レベルを設定する方法

1. 次のステートメントを使用して、トランザクションの分離レベルを変更します。

SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别;
#其中,隔离级别格式:
> READ UNCOMMITTED
> READ COMMITTED
> REPEATABLE READ
> SERIALIZABLE

# 或者:
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'
#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE

2. 設定時に GLOBAL または SESSION を使用した場合の影響について:

  1. GLOBAL キーワードを使用します (グローバル スコープに影響します)。
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET GLOBAL TRANSACTION_ISOLATION = 'SERIALIZABLE';

現在の既存のセッションは無効であり、ステートメントの実行後に生成されたセッションでのみ有効になります。

  1. SESSION キーワードを使用します (セッション スコープに影響します)。
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET SESSION TRANSACTION_ISOLATION = 'SERIALIZABLE';

その後: 現在のセッションの後続のすべてのトランザクションに対して有効です。トランザクション間で実行された場合は、後続のトランザクションに対して有効です。このステートメントは、すでに開かれているトランザクションの途中で実行できますが、現在実行中のトランザクションには影響しません。

データベースでは、複数のトランザクション分離レベルが規定されています。異なる分離レベルは、さまざまな程度の干渉に対応します。分離レベルが高いほど、データの一貫性は向上しますが、同時実行性は弱くなります。

さまざまな分離レベルの例

read-uncommitted未コミットの読み取り

ケースその1

ここに画像の説明を挿入します
2 つのトランザクションの分離レベルを非コミット読み取りに設定します。
画像の説明を追加してください
その後、トランザクション 1 がトランザクションを開始します。トランザクション 1 は、更新するデータは送信されません。トランザクション
画像の説明を追加してください
2 はこのデータを見つけることができ
画像の説明を追加してください
、トランザクション 1 はロールバックされますが、
画像の説明を追加してください
トランザクション 2 は見つかったばかりのデータです。ダーティデータです

ケース2

Zhang San は Li Si に 100 元を送金します。トランザクション 1 はトランザクションを開いてこの操作を実行しますが、送信しません。
画像の説明を追加してください
その後、トランザクション 2 のクエリにより、Zhang San が Li Si に 100 元を送金したことがわかりますが、Li Si はこれを望んでいません。100 , そこで、彼はそれを Zhang San に転送しました (転送するには、2 つの SQL を実行する必要がありました。1 つは自分用に -100、もう 1 つは Zhang San 用に +100、ここで最初に実行された SQL は -100 でした)。 update ステートメントがスタックしました。これは、トランザクション 1 がこの時点でトランザクションをコミットしておらず、まだ占有されているためです。データベースはロックされているため、トランザクション 2 の更新がここで待機しています。その後、トランザクション 1 で、Zhang San は次のことを行います
画像の説明を追加してください
。 Li Si に送金したくないため、トランザクション 1 がロールバックされます。
画像の説明を追加してください
トランザクション 1 がロールバックされた後、トランザクション 2 が待機している更新ステートメント (Li Si が Zhang San に 100 元を送金するステートメント) も実行されます。実行では、トランザクション 2 は Zhang San の +100 SQL を実行し続け、最終データベースをコミットします画像の説明を追加してください
。Zhang San のアカウントが 200 で、Li Si のアカウントが -100 であるのは不合理です。

読み取りコミット読み取りコミット

データを復元し (テーブルをクリアしてデータを追加)、トランザクション レベルを読み取りコミットに設定します。
画像の説明を追加してください
トランザクション 2 では、トランザクション レベルを読み取りコミットに設定する必要もあります。
画像の説明を追加してください
次に、トランザクション 1 でトランザクションを開いて操作します。コミットやロールバックを行わずに、データ (Zhang San のアカウントを 50 ブロック削減) を実行します。
画像の説明を追加してください
その後、トランザクション 2 がトランザクションを開始してデータをチェックします。データは変更されていません。これはダーティ リードを回避することと同じです。その後、トランザクション 1 が
画像の説明を追加してください
コミットし
画像の説明を追加してください
、トランザクション 2 が続行されます。元のトランザクションでクエリを実行します。データは最新です。変更されたデータ:
ここに画像の説明を挿入します
トランザクション 2 がデータを表示するトランザクションを開始し、別のトランザクションがデータを変更します。トランザクション 2 が検出するのは最新のデータであり、反復不可能な読み取りです。次に、トランザクション 2 がトランザクションをコミットしてデータを表示します。
ここに画像の説明を挿入します

反復可能読み取り 反復可能読み取り

上記に基づいて、反復可能読み取りのデモを続け、両方のトランザクションのトランザクション レベルを反復可能読み取りに設定し、トランザクション画像の説明を追加してください
1 でトランザクションをオープンすることで、Zhang San のアカウントが 10 減ります。
画像の説明を追加してください
トランザクション 2 はトランザクションをオープンし、クエリを実行します。Zhang San のアカウントは変更されておらず、まだ 50 です。
ここに画像の説明を挿入します
その後、トランザクション 1 がトランザクションを送信しました画像の説明を追加してください
。トランザクション 2 は、元のトランザクションでクエリされました。Zhang San のアカウントは変更されておらず、まだ 50 です。
画像の説明を追加してください
その後、トランザクション 2 がトランザクションを送信しました。反復可能な読み取り:
画像の説明を追加してください
トランザクション 1 はデータを操作するトランザクションを開き、トランザクション 2 はデータをクエリするトランザクションを開きます。トランザクション 1 がデータをどのように変更しても、トランザクション 1 がコミットまたはコミットしても、そうではなく、トランザクション 2 の同じトランザクションによって見つかったデータは常に同じになります。

幻の読書

トランザクション 2 では、トランザクションがオープンされ、id=3 のデータの数がクエリされますが、データが見つかりません。トランザクション 1 では、トランザクションがオープンされ、id
画像の説明を追加してください
=3 のデータがそこに挿入されて送信されます。
画像の説明を追加してください
次に、トランザクション 2 は元のトランザクションの id=3 のデータをクエリします。それでも見つからず、トランザクション 2 は id=3 のデータを挿入し、エラーが報告されました。これはファントム読み取りです
画像の説明を追加してください

画像の説明を追加してください
最後に、トランザクション 2 がロールバックされ、画像の説明を追加してください
シリアル化された分離レベルを使用してファントム読み取りの問題を解決できます。トランザクション 2 がトランザクションを開始し、id=3 のデータのクエリを実行した後、このデータはロックされ、トランザクション 1 が挿入します。 id=3 のデータ。データはスタックし、トランザクション 2 がコミットされた後もトランザクション 1 の操作が継続されます (トランザクション 1 が id=3 のデータを挿入しない場合、トランザクション 1 はスムーズに実行されます)。

取引の一般的なカテゴリ

トランザクション理論の観点から、トランザクションは次のタイプに分類できます。

  1. フラットトランザクション
  2. セーブポイントを使用したフラット トランザクション チェーン トランザクション
  3. ネストされたトランザクション
  4. 分散トランザクション

おすすめ

転載: blog.csdn.net/CaraYQ/article/details/129351650