この記事では、MySQL のトランザクション機能について説明し、マルチバージョン同時実行制御 MVCC の実装原理を紹介します。
トランザクションは通常、一連の論理的な操作を指します。単一の論理ユニットによって実行される一連の操作として。トランザクション内のすべての操作は、分割不可能な実行ユニットにカプセル化されます。このユニット内のすべての操作は、いずれかの操作が実行される限り、すべて正常に実行されるか、すべて失敗します。失敗すると、トランザクション全体がロールバックされます。
原子性(原子性)
トランザクションの原子性とは、トランザクションを構成するすべての操作がすべて正常に実行されるか、すべて失敗することを意味します。Consistency (一貫性)
トランザクションの一貫性とは、トランザクションの実行前後でデータが常に一貫した状態であることを意味します。分離
トランザクションの分離とは、同時に実行される 2 つのトランザクション間で干渉がないこと、つまり、プロセス中のトランザクションの実行を指します。他のトランザクション実行プロセスの中間ステータスを確認することはできません。?注: MySQL
は、
MVCCメカニズムをロックすることでトランザクションの分離を保証します。
永続性 (期間)
トランザクションの永続性とは、送信後のデータに対するこのトランザクションの変更操作を指します。データベースに永続化され、ロールバックされません。 #2.2 2 つのトランザクション タイプの概要通常、リレーショナル データベースに基づいて制御されるトランザクションは、従来のトランザクションまたはローカル トランザクションと呼ばれます。
#ローカル トランザクション実行プロセス
クライアントがトランザクション操作を開始する前に、有効にする必要があります 接続応答;
応答を開始した後、クライアントはトランザクションを開始する命令を開始します;
トランザクションの開始後, クライアントはさまざまな SQL ステートメント処理データを送信します;
通常の状況では、クライアントはトランザクション コミット コマンドを開始します。例外が発生した場合、クライアントはロールバック トランザクション コマンドを開始します。
#✔ローカル トランザクションは、リソース マネージャーによってローカルに管理されます。
ローカル トランザクションの欠点は次のとおりです。
分散トランザクションを処理する機能がない1 つのトランザクション プロセスで分散トランザクションを処理できます。接続のみ トランザクションをサポートするデータベースを複数のトランザクション データベースと一緒に使用することはできません。
つまり、後で送信されたトランザクション 2 がトランザクション 1 の更新操作を上書きします。 , これは、いわゆる更新ロスです。更新ロス (ダーティ ライト) は、本質的には書き込み操作の競合です。ただし、ダーティ ライトを解決する方法は、各トランザクションをシリアルに実行して、トランザクションが確実に書き込み操作を特定の順序で実行するようにすることです。 。
あるトランザクションは、コミットされていないデータを別のトランザクションから読み取ります。例: トランザクション 1 は Zhang San の残高に 100 元を追加します。このトランザクションが送信される前に、別のトランザクション 2 が変更中のデータを読み取ります。制御下にトランザクションがない場合は、2 番目のトランザクションがそれを読み取ります。コミットされていないデータが検出され、ダーティ データ クラスターを処理する次のステップで、コミットされていないデータへの依存関係が生成されます。この現象は通常、#Dirty Reading Non-repeatable read は本質的に、読み取り操作と書き込み操作の間で競合が発生します。解決策は、最初に読み取り、次に書き込みを行う、つまり、読み取り後に書き込みを行うことです。 ファントム読み取りは、本質的に読み取り操作と書き込み操作の間の競合です。解決策は、最初に読み取り、次に書き込みを行うこと、つまり、読み取り後に書き込みを行うことです。 この時点で、多くの友人が質問を持っています。同じ本質は、読み取り操作と書き込み操作の間の競合です。解決策は、最初に読み取り、次に書き込むことです。反復不可能な読み取りと書き込みの違いは何ですか?ファントム読み取り?、I 簡単な説明については以下を参照してください: 次のコマンドを使用して、グローバル レベルおよびセッション レベルのトランザクションをクエリします。分離レベル: ダーティ リーディング
と呼ばれます。 : ダーティ読み取りとは、あるトランザクションが、別のトランザクションによって送信されていないデータを読み取ることです。
Non-repeatable read
トランザクションは特定のデータを読み取ります。一定時間が経過すると、トランザクションは以前に読み取られたデータを再度読み取ります。データが見つかると、トランザクションはそのデータを再度読み取ります。読み取りデータが変更されたか、データ レコードの一部が削除された場合、この現象は非反復読み取りと呼ばれます。
は、同じクエリ ステートメントを使用した同じトランザクションが異なる時点で読み取られることを意味します。得られる結果は次のとおりです。一貫性がない。
#ファントム読み取り
トランザクションは、同じクエリ条件に従って以前に読み取られたデータを再読み取りします。このとき、他のトランザクションが読み取りを行っていることがわかります。現在のクエリ条件を満たすデータが挿入されました。新しいデータでは、データの結果セットが大きくなります。この現象はファントム読み取りと呼ばれます。つまり、トランザクションはデータ レコードの範囲を 2 回読み取りますが、2 回読み取られた結果は異なります。
1️⃣ 非反復読み取りの焦点は更新および削除操作ですが、ファントム読み取りの焦点は挿入操作です。
4. MySQL トランザクション分離レベル
# 默认数据库的事务隔离级别为:可重复读(REPEATABLE-READ)
SELECT @@global.tx_isolation;
SELECT @@session.tx_isolation;
SELECT @@tx_isolation;
#5. マルチバージョン同時実行制御 MVCC
MVCCは同時実行制御方式であり、データベースへの同時アクセスを実現するためにデータベース管理システムで一般に使用されます。
ロックに対する MVCC の利点
MVCC
的是通过保存数据澡某个时间点的快照来实现的,也就是说,不管事务执行多长的时间,每个事务看到的数据都是一致的。根据事务的开始时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。InnonDB
主要通过为每一行记录添加两个额外的隐藏的值来实现MVCC
,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB
并不存储这些事件发生时的 实际时间 ,相反它只存储这些事件发生时的系统 版本号(version) 。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。
《高性能MySQL》书籍中介绍到:
MVCC
只在REPEATABLE READ
和READ COMMITTIED
两个隔离级别下工作,其他两个隔离级别都和MVCC
不兼容,因为READ UNCOMMITTED
总是读取最新的数据行,而不符合当前事务版本数据行,而SERIALIZABLE
串行化隔离级别则会对所有读取的行都加锁。
接下来举个例子说明在可重复读事务隔离级别下,MVCC
机制是如何完成增删改查操作的。
在查询操作中,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的两条查询语句的到的结果始终是一致的。
在插入操作中,InnoDB
会将新插入的每一条行记录的当前系统版本包保存为行版本号。
比如:向account
表插入一条数据,同时MVCC
的两个版本号分别为create_version
和delete_version
,create_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 | 未定义 |
可以看出,当向数据表新增记录时,需要设置保存行的版本号,而删除行的版本号未定义。
在更新操作中,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中。
在删除操作中,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 サイトの他の関連記事を参照してください。