ホームページ  >  記事  >  データベース  >  MySQL のオプティミスティック ロックとペシミスティック ロック固有の実装

MySQL のオプティミスティック ロックとペシミスティック ロック固有の実装

WBOY
WBOY転載
2022-09-07 14:23:172604ブラウズ

推奨学習: mysql ビデオ チュートリアル

多くの開発者は、MySQL の楽観的ロックと悲観的ロックについて知らないかもしれません。しかし、それがどのように実装されているかはわかりません。この記事では、2 つのロックの違いを完全に理解できるように、この問題に関する実践的な事例を示します。

ロックの分類

MySQL のロックは、その範囲に応じて主にテーブル ロック、行ロック、ページ ロックに分類されます。 myisam ストレージ エンジンはテーブル ロックのみをサポートしますが、InnoDB は行ロックだけでなく、ある程度のテーブル ロックもサポートします。動作に応じて、共有ロック (読み取りロック)、排他ロック (書き込みロック)、および意図ロックに分類できます。彼らの考え方に応じて、楽観的なロックと悲観的なロックに分類されます。

今日の記事では、楽観的ロックと悲観的ロックが実際にどのように動作するかを示します。

#テーブル構造

次の SQL ステートメントはテーブルの構造です:

CREATE TABLE `demo`.`user` (
`id` int(10) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`sex` tinyint(1) UNSIGNED NOT NULL DEFAULT 0,
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`version` int(1) NULL DEFAULT 1 COMMENT '数据版本号',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

シミュレートされたデータの挿入:

BEGIN;
INSERT INTO `user` VALUES (0000000001, '张三', 0, '18228937997@163.com', '18228937997', 1);
INSERT INTO `user` VALUES (0000000002, '李四', 0, '1005349393@163.com', '15683202302', 1);
INSERT INTO `user` VALUES (0000000003, '李四1', 0, '1005349393@163.com', '15683202302', 1);
INSERT INTO `user` VALUES (0000000004, '李四2', 0, '1005349393@163.com', '15683202302', 1);
INSERT INTO `user` VALUES (0000000005, '李四3', 0, '1005349393@163.com', '15683202302', 1);
INSERT INTO `user` VALUES (0000000006, '李四4', 0, '1005349393@163.com', '15683202302', 1);
INSERT INTO `user` VALUES (0000000007, '李四55', 0, '1005349393@163.com', '15683202302', 1);
COMMIT;

テーブル内のデータ。

mysql root@127.0.0.1:demo> select * from user;
+----+--------+-----+---------------------+-------------+---------+
| id | name | sex | email | mobile | version |
+----+--------+-----+---------------------+-------------+---------+
| 1 | 张三 | 0 | 18228937997@163.com | 18228937997 | 2 |
| 2 | 李四 | 0 | 1005349393@163.com | 15683202302 | 1 |
| 3 | 李四1 | 0 | 1005349393@163.com | 15683202302 | 1 |
| 4 | 李四2 | 0 | 1005349393@163.com | 15683202302 | 1 |
| 5 | 李四3 | 0 | 1005349393@163.com | 15683202302 | 1 |
| 6 | 李四4 | 0 | 1005349393@163.com | 15683202302 | 1 |
| 7 | 李四55 | 0 | 1005349393@163.com | 15683202302 | 1 |
+----+--------+-----+---------------------+-------------+---------+
7 rows in set
Time: 0.011s

悲観的ロック

悲観的ロックは、比較的ネガティブなロック処理方法です。データを操作するときは、直接ロックを取得してください。進行中の他のトランザクションは、ロックを保持しているトランザクションがロックを解放するまで待機します。

この処理方法では、データの一貫性を最大限に確保できますが、ロック タイムアウトや同時実行性の低下などの問題が発生しやすくなります。まずトランザクション 1 を開始し、id=1 でデータを更新しますが、この時点ではトランザクションは送信しません。

mysql root@127.0.0.1:demo> begin;
Query OK, 0 rows affected
Time: 0.002s
mysql root@127.0.0.1:demo> update `user` set name = '张三111111'where id = 1;
Query OK, 1 row affected
Time: 0.004s

次に、トランザクション 2 を開始し、id=1 でデータを更新して、この時点で何が起こるかを確認します。

mysql root@127.0.0.1:demo> begin;
Query OK, 0 rows affected
Time: 0.002s
mysql root@127.0.0.1:demo> update `user` set sex = 1 where id = 1;

update ステートメントを実行した後は待機状態となり、トランザクションがコミットされていないと ID のデータに対応する書き込みロックが解除されるため、SQL ステートメントはすぐには実行されません。 =1は解除されません。

効果は次のとおりです。

MySQL のオプティミスティック ロックとペシミスティック ロック固有の実装

##上記の例を通じて、さらに多くのことが可能になります。悲観的ロックの実装プロセスを直感的に感じてください。

オプティミスティック ロック

オプティミスティック ロックでは、通常の状況ではデータが競合を引き起こすことはないと考えられます。データの競合は、データが変更された場合にのみ処理されます。ここで矛盾はどのようにして発見されるのでしょうか?従来の方法では、バージョン番号やタイムスタンプなどのフィールドをデータ行に追加します。 (この記事では、バージョンを管理するための適切な方法としてバージョンを使用し、同じ理由でタイムスタンプを使用します)

オプティミスティック ロックの実装原則:

トランザクションはデータを読み取り、この時点のバージョン番号が 1 であると仮定して、対応するバージョン番号フィールドを読み取ります。
  • 別のトランザクションも同じ読み取り操作を実行します。トランザクションがコミットされると、バージョン番号に 1 が実行されますが、このときのデータ行のバージョン番号は 2 になります。
  • 2 番目のトランザクションが変更操作を実行すると、ビジネス データに基づいて条件が作成され、デフォルトでバージョン番号が where 条件として追加されます。この時点では、変更ステートメントのバージョン番号フィールドが where 条件を満たしていないため、トランザクションの実行は失敗します。このようにして、ロック機能が実現される。

MySQL のオプティミスティック ロックとペシミスティック ロック固有の実装

クライアント 1:

mysql root@127.0.0.1:demo> select * from user where id = 1;
+----+------------+-----+---------------------+-------------+---------+
| id | name | sex | email | mobile | version |
+----+------------+-----+---------------------+-------------+---------+
| 1 | 张三111111 | 0 | 18228937997@163.com | 18228937997 | 1 |
+----+------------+-----+---------------------+-------------+---------+
1 row in set
Time: 0.012s
mysql root@127.0.0.1:demo> update `user` set name = '事务一', version = version + 1 where id = 1 and version = 1;
Query OK, 1 row affected
Time: 0.008s
mysql root@127.0.0.1:demo> select * from user where id = 1;
+----+--------+-----+---------------------+-------------+---------+
| id | name | sex | email | mobile | version |
+----+--------+-----+---------------------+-------------+---------+
| 1 | 事务一 | 1 | 18228937997@163.com | 18228937997 | 2 |
+----+--------+-----+---------------------+-------------+---------+
1 row in set
Time: 0.009s

更新ステートメントの実行順序は、 client 2. 選択を実行した後、実行します。

クライアント 2:

mysql root@127.0.0.1:demo> select * from user where id = 1;
+----+------------+-----+---------------------+-------------+---------+
| id | name | sex | email | mobile | version |
+----+------------+-----+---------------------+-------------+---------+
| 1 | 张三111111 | 1 | 18228937997@163.com | 18228937997 | 1 |
+----+------------+-----+---------------------+-------------+---------+
1 row in set
Time: 0.015s
mysql root@127.0.0.1:demo> update `user` set name = '事务二', version = version + 1 where id = 1 and version = 1;
Query OK, 0 rows affected
Time: 0.003s
mysql root@127.0.0.1:demo> select * from user where id = 1;
+----+--------+-----+---------------------+-------------+---------+
| id | name | sex | email | mobile | version |
+----+--------+-----+---------------------+-------------+---------+
| 1 | 事务一 | 1 | 18228937997@163.com | 18228937997 | 2 |
+----+--------+-----+---------------------+-------------+---------+
1 row in set
Time: 0.012s
この時点で、update によって返された構造によれば、影響を受ける行の数は 0 であることがわかります。選択クエリの後、キャッシュバック データはトランザクション 1 のデータでもあります。

適用可能なシナリオ

悲観的ロック:

書き込み操作がより頻繁に行われるシナリオに適しており、読み取り操作が多数ある場合は追加されます。これにより、ロックのオーバーヘッドが大幅に増加し、システムのスループットが低下します。

オプティミスティック ロック:

は、読み取り操作がより頻繁に行われるシナリオに適しています。大量の書き込み操作が発生すると、データ競合の可能性が高くなります。一貫性を確保するため、データの増加に伴い、アプリケーション層は常にデータを再取得する必要があるため、クエリ操作の数が増加し、システムのスループットが低下します。 概要

どちらのタイプにも独自の長所と短所があり、楽観的ロックは頻繁な読み取りに使用され、悲観的ロックは頻繁な書き込みに使用されます。

オプティミスティック ロックは、書き込みが比較的少ない状況、つまり競合がほとんど発生しない状況に適しています。これにより、ロックのコストが節約され、システム全体のスループットが向上します。ただし、頻繁に競合が発生すると、上位層のアプリケーションがリトライを繰り返すことになり、かえってパフォーマンスが低下するため、この場合には悲観的ロックを使用する方が適切です。つまり、競合が深刻な場合は、悲観的ロックが使用されます。

悲観的ロックは強い整合性のシナリオにより適していますが、効率は比較的低く、特に読み取りの同時実行性が低くなります。オプティミスティック ロックは、読み取りが多く書き込みが少なく、同時実行性の競合が少ないシナリオに適しています。

推奨学習: mysql ビデオ チュートリアル

以上がMySQL のオプティミスティック ロックとペシミスティック ロック固有の実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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