推奨学習: 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は解除されません。
効果は次のとおりです。
##上記の例を通じて、さらに多くのことが可能になります。悲観的ロックの実装プロセスを直感的に感じてください。
オプティミスティック ロック
トランザクションはデータを読み取り、この時点のバージョン番号が 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
クライアント 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 サイトの他の関連記事を参照してください。