データベーストランザクション(2)------ Mysqlデータベースロック

データベーストランザクション分離レベルのダーティ読み取り、仮想読み取り、繰り返し不可能な読み取りについてはすでに理解していますが、データベースをより適切に操作し、データベースの読み取りと書き込みのパフォーマンスを向上させたい場合は、データベースの別のメカニズムも理解する必要があります。 -データベースロック!

実際、mysqlデータベースを長期間使用したばかりのパートナーは、データベースのロックについて何も知らない可能性があり、それでも質問がある可能性があります。データベースはデッドロックされていますか?データベースがデッドロックしている場合、それはGGではありませんか?最初に確認することは、もちろんデータベースがデッドロックすることです。トランザクション、分離、および同時実行性があるため、ロジックが適切に処理されないと、デッドロックが確実に発生します。

これに遭遇したことのないほとんどの小規模パートナーについては、1つは、さらされる可能性のあるビジネスの同時実行性がそれほど高くないこと、ビジネスロジックが特に複雑ではないこと、およびもう1つの重要な理由は内部にデッドロック監視メカニズムがあることです。データベース。データベースがデッドロックであることが判明すると、ロールバック操作がトリガーされ、データベースが実際にダウンすることはありません。

データベースのロックについて理解しましょう。これはデータ分離であるため、同時実行性の高い操作データはロックする必要があります。そうしないと、混乱してしまいます。ロックについて知ると、デッドロックメカニズムは非常に単純であり、Javaコードを使用してデッドロックを実現するのと同じように、デッドロックビジネスオペレーションを簡単に記述できます。

Java(共通)のロックは一般に楽観的ロック(CAS)であり、AQSを継承することによって実装されるロックは、ペアリングをブロックすることによって実装され、同期モニターによって実装されるロックがあります。MySQLはどうですか?Javaは言語であり、主にプログラムの実行に必要なデータロジックまたはリソースをロックすることを目的としています。メインのロックはリソースですが、MySQLデータベースについてはどうでしょうか。これはリレーショナルデータベースであり、ロックは主にデータをロックしてダーティリードなどのイベントを防止するためのものであるため、2つのロックには違いがあるはずです。

MySQLロック、主に行ロック(レコードロック)、ギャップロック(近位キーロック)、インテンションロック(インテンションロックの挿入)、自動インクロックなどを見てみましょう。

1.行ロック

最初にデータテーブルを作成して、操作を見て明確になるようにします。以下は、テーブルといくつかのデータを作成するためのsqlステートメントです。

CREATE TABLE `student`  (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id主键',
  `age` int(11) NULL DEFAULT NULL COMMENT '年龄',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '名称',
  `id_card` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '身份证号',
  `stage` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '等级',
  `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建日期',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `idx_card`(`id_card`) USING BTREE COMMENT '唯一索引--身份编号',
  INDEX `idx_stage`(`stage`) USING BTREE COMMENT '普通索引--等级索引'
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '个人测试索引-学生表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, 16, '张三', '110120200402023456', '9', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (2, 16, '张三加', '110120200402023454', '9', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (3, 16, '张四', '110120200402023457', '8', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (4, 16, '张五', '110120200402023458', '7', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (5, 16, '张六', '110120200402023459', '6', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (6, 16, '张七', '110120200402023460', '5', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (7, 16, '张八', '110120200402023465', '4', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (8, 16, '张九', '110120200402023466', '15', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (9, 16, '张氏', '110120200402023467', '16', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (10, 16, '李四', '110120200402023480', '18', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (11, 16, '李五', '110120200402023481', '19', '2020-10-21 14:07:15');
INSERT INTO `student` VALUES (12, 16, '李六', '110120200402023482', '20', '2020-10-21 14:07:15');

写真を切って、はっきり見てください〜

mysql学生データテーブル、一意のインデックスid_card、通常のインデックスステージ

ロック解除について説明する前に、まず分離レベルのビューを理解しましょう。これは次のステートメントです。

現在の分離レベルとして@@ tx_isolationを選択し、グローバル分離レベルとして@@ global.tx_isolationを選択します。 
トランザクションの分離レベルはロックに影響を与えます。ロック操作を実行する前に、の分離レベルを確認することをお勧めします。もちろん、MySQLのデフォルトはREPEATABLE-READです。

さて、これらのSQLステートメントを見てみましょう。

-- 开启事务A 
START TRANSACTION;
-- id=7的数据 
SELECT * FROM student where id=7 for UPDATE;  
-- --上半部分
-- ----------
-- --下半部分
ROLLBACK;

-- ----最好在可视化工具的两个查询页面,方便看结果

-- 启动事务B
START TRANSACTION ;
-- id=7的数据 
SELECT * FROM student where id=7 for UPDATE;  

-- --上半部分
-- ----------
-- --下半部分
ROLLBACK;

       クエリステートメントの後に更新を追加することは、学生テーブル全体にインテンションロックを追加し(以下で説明)、クエリの結果データをロックするid = 7のレコードに排他ロックを追加することです。実際、更新(変更用)の場合は変更する必要があることは明らかであり、他の人に変更を許可してはなりません。そうしないと、変更を一緒に行ってもセットが台無しになりません。

トランザクションAの上半分を実行すると、id = 7のデータがロックされ、トランザクションAは終了していません。次に、トランザクションBを開始し、Li Siに再度クエリを実行します(更新用)。LiSiのデータをクエリできないことがわかります。トランザクションは実行中であり、エラーメッセージは表示されません。実際、トランザクションの終了を待機しています。 A(送信または返却)。ロール)。もちろん、トランザクションBがid = 8のデータを照会する場合、問題はありません

実際、この時点で、行ロックはid = 7のデータに追加されます。

ダウンロックの公式説明を見てみましょう。レコードロックはインデックスレコードのロックです 行ロックはインデックスで使用する必要があります)。       

学生テーブルのID(テーブルの作成時にクラスター化インデックスが追加されました)、idx_card、idx_stageはすべてインデックスが付けられます。これらの条件下でロック操作を実行すると、このデータがロックされます。

行ロックには次の2つのタイプがあります。

  • 共有ロック(S) 共有ロックは読み取りロックとも呼ばれます。読み取りロックを使用すると、複数の接続が互いに干渉することなく、同じリソースを同時に読み取ることができます。

  • 排他ロック(X) 排他ロックは書き込みロックとも呼ばれます。書き込みロックは他の書き込みロックまたは読み取りロックをブロックし、他のユーザーがこのデータを読み書きできないようにしながら、1つの接続のみが同時にデータを書き込むことができるようにします。

ただし、名前などのフィールドにインデックスが付けられていないことが条件で、データをロックする場合は、テーブルロックしか使用できません。この場合、より多くのリソースを消費し、デッドロックが発生しやすくなります。

2.ギャップロック 

インデックス条件でクエリを実行すると、行ロックが実行されることを確認しました。では、ギャップロックとは何ですか。次のステートメントを見てみましょう。

-- 开启事务A 
START TRANSACTION;
-- id_card大于'110120200402023465',小于'110120200402023481'的数据 
SELECT * FROM student where id_card>'110120200402023465' and id_card <'110120200402023481' for UPDATE
-- --上半部分
-- ----------
-- --下半部分
ROLLBACK;

-- -----------------------------------------------------------

-- 启动事务B
START TRANSACTION ;
-- 删除 id_card='110120200402023481' 的数据 
DELETE FROM student where id_card='110120200402023481';

-- --上半部分
-- ----------
-- --下半部分
ROLLBACK;

トランザクションAの上半分を実行し、id_cardが「110120200402023465」より大きく「110120200402023481」より小さいデータをロックします。この時点で、id_cardは「110120200402023465」より大きく「110120200402023481」より小さくなっています。このデータセグメントはロックされています。 。id_card=を挿入した場合110120200402023469のデータは失敗している必要があります。

しかし、トランザクションBの上部を実行するとどうなりますか?id_cardが「110120200402023481」未満ですが、「110120200402023481」はロックされていませんか?もちろんそうではありません。SQLステートメントを実行すると、トランザクションBがトランザクションAのロールバックまで待機していることがわかります。トランザクションBは引き続き実行できます。明らかに、id_cardデータが「110120200402023481」のデータはロックされています。

クエリ関連の概念では、ギャップロックロックの戦略が開いたままで、右が閉じていることがわかります。間隔をロックすると、左側のデータはロックされず、右側のデータはロックされます。したがって、トランザクションAのロックされた間隔は( '110120200402023465'、 '110120200402023481']です。試してみることができます。id_card= 110120200402023465が操作されている場合、トランザクションBはロックされません。

ギャップロックを使用すると、特定のセグメントがロックされます。このようにして、一部の制御でファントム読み取りの発生を実際に回避できます。同時に、データベースのパフォーマンスを確保するために、最小範囲のロックが実行されます。

もちろん、ギャップロックはインデックス用でもあり、インデックスがない場合はテーブルが直接ロックされます。

3.インテントロック

行レベルのロックとテーブルレベルのロックを共存させる複数粒度ロックをサポートするために、インテンションロックが導入されています。意図的なロックとは、将来のある時点で、トランザクションを共有/排他的にロックする必要があり、インテントが事前に宣言されることを意味します。

SELECT * FROM Student where id_card> '110120200402023465' and id_card <'110120200402023481' for UPDATE

これは実際には意図的なロックです。

  1. インテントロックは、テーブルレベルのロック(テーブルレベルのロック)です。
  2. インテントロックは次のように分けられます。
    • インテンション共有ロック(インテンション共有ロック、IS)、トランザクションがテーブルの特定の行に共有Sロックを追加することを意図していることを示します
    • 意図的排他ロック(IX)、トランザクションがテーブル内の特定の行に排他的Xロックを追加することを意図していることを示します

 文法:

選択...共有モードでロック; ISロック
       を設定するには;更新のために...を選択; IXロックを設定するには;

以下は、意図ロックとSロックおよびXロックの相互排除関係です。 

 

 自己インクリメントロックについては、誰もが使っていると思います。テーブルを作成するたびに、IDは通常自己インクリメントに設定されます。実際、ここに自己インクリメントロックが追加されます。

さて、データベースロックはここで停止します。

犠牲も勝利もありません〜

おすすめ

転載: blog.csdn.net/zsah2011/article/details/109149721