ホームページ  >  記事  >  データベース  >  MySQL のトランザクション機能と実装原則についての詳細なチャット

MySQL のトランザクション機能と実装原則についての詳細なチャット

青灯夜游
青灯夜游転載
2023-02-10 19:55:171441ブラウズ

この記事では、MySQL のトランザクション機能について説明し、マルチバージョン同時実行制御 MVCC の実装原理を紹介します。

MySQL のトランザクション機能と実装原則についての詳細なチャット

1. 概念

トランザクションは通常、一連の論理的な操作を指します。単一の論理ユニットによって実行される一連の操作として。トランザクション内のすべての操作は、分割不可能な実行ユニットにカプセル化されます。このユニット内のすべての操作は、いずれかの操作が実行される限り、すべて正常に実行されるか、すべて失敗します。失敗すると、トランザクション全体がロールバックされます。

#2. トランザクションの特性とタイプの概要

2.1 トランザクションの特性

MySQL のトランザクション機能と実装原則についての詳細なチャット

原子性(原子性)

トランザクションの原子性とは、トランザクションを構成するすべての操作がすべて正常に実行されるか、すべて失敗することを意味します。

Consistency (一貫性)

トランザクションの一貫性とは、トランザクションの実行前後でデータが常に一貫した状態であることを意味します。

分離

トランザクションの分離とは、同時に実行される 2 つのトランザクション間で干渉がないこと、つまり、プロセス中のトランザクションの実行を指します。他のトランザクション実行プロセスの中間ステータスを確認することはできません。

?‍注: MySQL は、MVCC メカニズムをロックすることでトランザクションの分離を保証します。

永続性 (期間)

トランザクションの永続性とは、送信後のデータに対するこのトランザクションの変更操作を指します。データベースに永続化され、ロールバックされません。

#2.2 2 つのトランザクション タイプの概要

ローカル トランザクション
  • 分散トランザクション
  • ## ローカル トランザクション

通常、リレーショナル データベースに基づいて制御されるトランザクションは、従来のトランザクションまたはローカル トランザクションと呼ばれます。

#ローカル トランザクション実行プロセス

MySQL のトランザクション機能と実装原則についての詳細なチャットクライアントがトランザクション操作を開始する前に、有効にする必要があります 接​​続応答;

  • 応答を開始した後、クライアントはトランザクションを開始する命令を開始します;

  • トランザクションの開始後, クライアントはさまざまな SQL ステートメント処理データを送信します;

  • 通常の状況では、クライアントはトランザクション コミット コマンドを開始します。例外が発生した場合、クライアントはロールバック トランザクション コマンドを開始します。

  • ##上記のプロセスが完了したら、セッションを閉じます。

  • #✔ローカル トランザクションは、リソース マネージャーによってローカルに管理されます。

ローカル トランザクションの欠点は次のとおりです。

分散トランザクションを処理する機能がない1 つのトランザクション プロセスで分散トランザクションを処理できます。接続のみ トランザクションをサポートするデータベースを複数のトランザクション データベースと一緒に使用することはできません。

  • 3. 同時トランザクションはどのような問題を引き起こしますか?

更新損失 (ダーティ ライト)

MySQL のトランザクション機能と実装原則についての詳細なチャット

複数のトランザクションが同じデータ行を同時に操作し、最初に選択された値でデータ行を更新する場合、トランザクションは互いの存在を認識できないと見なされます。最後の更新操作は、以前に他のトランザクションによって完了した更新操作を上書きします。

例:

Zhang San の口座は 100 元です。現在、トランザクション 1 とトランザクション 2 の 2 つのトランザクションがあります。トランザクション 1 は、Zhang San の残高を送金することです。アカウントに 100 元を追加します。トランザクション 2 は Zhang San の残高を 200 増やします。最初、トランザクション 1 とトランザクション 2 は Zhang San の口座残高 100 元を同時に読み取ります。次に、トランザクション 1 とトランザクション 2 がそれぞれ Zhang Sanyue を更新します。トランザクション 1 が最初であると仮定します。トランザクション 2 で送信されましたが、最近の 2 つのトランザクションが送信された後の Zhang San の残高は 300 元です (通常は 400 元であるはずです)。

つまり、後で送信されたトランザクション 2 がトランザクション 1 の更新操作を上書きします。 , これは、いわゆる更新ロスです。更新ロス (ダーティ ライト) は、本質的には書き込み操作の競合です。ただし、ダーティ ライトを解決する方法は、各トランザクションをシリアルに実行して、トランザクションが確実に書き込み操作を特定の順序で実行するようにすることです。 。

ダーティ リーディング

あるトランザクションは、コミットされていないデータを別のトランザクションから読み取ります。例: トランザクション 1 は Zhang San の残高に 100 元を追加します。このトランザクションが送信される前に、別のトランザクション 2 が変更中のデータを読み取ります。制御下にトランザクションがない場合は、2 番目のトランザクションがそれを読み取ります。コミットされていないデータが検出され、ダーティ データ クラスターを処理する次のステップで、コミットされていないデータへの依存関係が生成されます。この現象は通常、#Dirty Reading と呼ばれます。 : ダーティ読み取りとは、あるトランザクションが、別のトランザクションによって送信されていないデータを読み取ることです。

MySQL のトランザクション機能と実装原則についての詳細なチャット

#?ダーティ リードは本質的に、読み取り操作と書き込み操作の間の競合です。解決策は、最初に書き込んでから読み取る、つまり、書き込んでから読み取ることです。 。

Non-repeatable read

トランザクションは特定のデータを読み取ります。一定時間が経過すると、トランザクションは以前に読み取られたデータを再度読み取ります。データが見つかると、トランザクションはそのデータを再度読み取ります。読み取りデータが変更されたか、データ レコードの一部が削除された場合、この現象は非反復読み取りと呼ばれます。

は、同じクエリ ステートメントを使用した同じトランザクションが異なる時点で読み取られることを意味します。得られる結果は次のとおりです。一貫性がない。

Non-repeatable read は本質的に、読み取り操作と書き込み操作の間で競合が発生します。解決策は、最初に読み取り、次に書き込みを行う、つまり、読み取り後に書き込みを行うことです。

#ファントム読み取り

トランザクションは、同じクエリ条件に従って以前に読み取られたデータを再読み取りします。このとき、他のトランザクションが読み取りを行っていることがわかります。現在のクエリ条件を満たすデータが挿入されました。新しいデータでは、データの結果セットが大きくなります。この現象はファントム読み取りと呼ばれます。つまり、トランザクションはデータ レコードの範囲を 2 回読み取りますが、2 回読み取られた結果は異なります。

ファントム読み取りは、本質的に読み取り操作と書き込み操作の間の競合です。解決策は、最初に読み取り、次に書き込みを行うこと、つまり、読み取り後に書き込みを行うことです。

この時点で、多くの友人が質問を持っています。同じ本質は、読み取り操作と書き込み操作の間の競合です。解決策は、最初に読み取り、次に書き込むことです。反復不可能な読み取りと書き込みの違いは何ですか?ファントム読み取り?、I 簡単な説明については以下を参照してください:

1️⃣ 非反復読み取りの焦点は更新および削除操作ですが、ファントム読み取りの焦点は挿入操作です。
  • 2️⃣ MySQL がロック メカニズムを使用してトランザクション分離レベルを実装する場合、反復読み取り分離レベルでは、最初の SQL ステートメントがデータを読み取った後、対応するデータがロックされます。他のトランザクションはこれらのデータを変更したり削除したりすることはできず、ロックによって反復可能な読み取りが実現されます。ただし、このメソッドでは新しいデータの挿入をロックできません。トランザクション 1 がデータを読み取るか、データを変更または削除する場合、トランザクション 2 も挿入操作を実行することができ、その結果、トランザクション 1 が不可解にも使用できなかったデータを追加することになります。これは幻の読書です。
  • 3️⃣ したがって、ロック メカニズムではファントム読み取りを回避することはできません。シリアル化されたトランザクション分離レベルを使用する必要がありますが、このトランザクション分離レベルではデータベースの同時実行機能が大幅に低下します。
  • ✔MySQL は、MVCC (Multiple Version Concurrency Control) メカニズムを使用して、非反復読み取りとファントム読み取りを回避します。

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

次のコマンドを使用して、グローバル レベルおよびセッション レベルのトランザクションをクエリします。分離レベル: MySQL のトランザクション機能と実装原則についての詳細なチャット

# 默认数据库的事务隔离级别为:可重复读(REPEATABLE-READ)
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;

#5. マルチバージョン同時実行制御 MVCCMySQL のトランザクション機能と実装原則についての詳細なチャット

マルチバージョン同時実行制御

マルチバージョン同時実行制御
MVCC

は同時実行制御方式であり、データベースへの同時アクセスを実現するためにデータベース管理システムで一般に使用されます。 ロックに対する MVCC の利点

MVCC は、行レベルのロックを妥協したものと考えることができます。ロックを使用すると、オーバーヘッドを小さくできます。実装によっては、ノンブロッキング読み取りを許可し、書き込み中に必要なレコードのみをロックできます。

MVCC的实现原理

MVCC的是通过保存数据澡某个时间点的快照来实现的,也就是说,不管事务执行多长的时间,每个事务看到的数据都是一致的。根据事务的开始时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。InnonDB主要通过为每一行记录添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB并不存储这些事件发生时的 实际时间 ,相反它只存储这些事件发生时的系统 版本号(version) 。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。

《高性能MySQL》书籍中介绍到:

MVCC只在REPEATABLE READREAD COMMITTIED两个隔离级别下工作,其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不符合当前事务版本数据行,而SERIALIZABLE串行化隔离级别则会对所有读取的行都加锁。

接下来举个例子说明在可重复读事务隔离级别下,MVCC机制是如何完成增删改查操作的。

  • 查询操作(SELECT)

在查询操作中,InnoDB存储引擎跟根据以下两个条件查询对应的行记录,只有满足对应条件才会被返回:

1️⃣ 只查找不晚于当前事务版本的数据行,也就是说,InnoDB存储引擎只会查找版本号小于或者等于当前事务版本的数据行,这些数据行要么在该事务开始前就存在,要么就是事务本身插入或者更新的行。
2️⃣ 对于数据删除,数据行删除的版本要么还没有被定义,要么大于当前事务的版本号,只有这样才能确保事务读到的行,在事务开始前并没有被删除。

举个例子,存在 事务A事务B 两个事务,事务A中存在两套相同的SELECT语句,事务B存在一条UPDATE语句,事务A 的第一条查询语句在事务B提交之前执行,第二条查询语句在 事务B 提交之后执行,事务A 如下所示:

-- 事务A操作
START TRANSACTION;
SELECT * FROM account WHERE id = 1;     //在事务B提交之前执行
SELECT * FROM account WHERE id = 1;     //在事务B提交之后执行
COMMIT;

事务B:

-- 事务B操作
START TRANSACTION;
UPDATE account SET balance = balance+100 WHERE id = 1;
COMMIT;

✔结论:如果没有使用MVCC机制,则事务A中的第一条SELECT语句读取的数据是修改前的数据,而第二条SELECT语句读取的是修改后的数据,两次读取的数据不一致,想想,那不就乱了吗?? 如果使用了MVCC机制,无论事务B如何修改数据,事务A的两条查询语句的到的结果始终是一致的。

  • 插入操作(SELECT)

在插入操作中,InnoDB会将新插入的每一条行记录的当前系统版本包保存为行版本号。

比如:向account表插入一条数据,同时MVCC的两个版本号分别为create_versiondelete_versioncreate_version代表创建行的版本号,delete_version代表删除行的版本号,另外还有一个事务ID字段,如下面所示:

INSERT INTO account(id, name, balance) values(1001, 'austin', 100);

对应的版本号信息如下表:

id name balance transaction_id create_version delete_version
1001 austin 100 1 1 未定义

可以看出,当向数据表新增记录时,需要设置保存行的版本号,而删除行的版本号未定义。

  • 更新操作(SELECT)

在更新操作中,InnoDB存储引擎会插入一行新记录,并保存当前系统的版本号为新记录行的版本号,同时保存当前系统的版本号到原来数据行作为删除标识。比如:将account数据表中id为1001的用户账户月增加100元,对应SQL如下:

UPDATE account SET balance = balance+100 WHERE id = 1001;

执行SQL, 在MVCC机制下的更新操作如下表所示:

id name balance transaction_id create_version delete_version
1001 austin 100 1 1 2
1001 austin 200 2 2 未定义

可以明显看出,执行更新操作时,MVCC机制是先将原来的数据复制一份,将balance字段增加100后,再讲create_version字段的值设置为当前系统的版本号,而delete_version字段的值未定义。

注意的是:原来的行会被复制到Undo Log中。

  • 删除操作(SELECT)

在删除操作中,InnoDB存储引擎会保存删除的每一个行记录当前的系统版本号,作为删除标识。比如:删除account数据表中id为1001的数据,SQL如下所示:

DELETE FROM account WHERE id = 1001;

对应MVCC机制下的删除操作如下表所示:

id name balance transaction_id create_version delete_version
1001 austin 200 3 2 3

可以看出,当删除数据表数据行时,MVCC机制会将当前系统的版本号写入删除数据行版本字段delete_version中,以此来表示当前数据行已经被删除。

六、总结

本文主要讲述了事务的特性、类型和本地事务和分布式事务的区别,通过不同的示例解释并发事务带来的更新丢失、脏读、不可重复读、幻读的问题,同时介绍了多版本并发控制MVCC的实现原理,如果文章对你有帮助,感谢点赞?+评论?+收藏❤,我是:?‍?austin流川枫,我们下期见!

【相关推荐:mysql视频教程

以上がMySQL のトランザクション機能と実装原則についての詳細なチャットの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。