MySQL の悲観的ロックと楽観的ロックの理解と応用分析

MySQL の悲観的ロックと楽観的ロックの理解と応用分析

この記事では、例を使用して MySQL の悲観的ロックと楽観的ロックについて説明します。ご参考までに、詳細は以下の通りです。

悲観的ロックと楽観的ロックは、人間が定義した概念です。並行リソースを処理するための一般的な手段である一種の考え方として理解できます。

これらを、MySQL で提供されているロック メカニズム (テーブル ロック、行ロック、排他ロック、共有ロック) と混同しないでください。

1. 悲観的ロック

名前が示すように、データ処理に対して悲観的であり、同時実行の競合が発生することを常に信じ、データを取得および変更するときに他の人がデータを変更することを意味します。したがって、データ処理プロセス全体を通じてデータをロックする必要があります。

悲観的ロックの実装は通常、MySQL の排他ロック、select .... for update などのデータベースが提供するロック メカニズムに依存して悲観的ロックを実装します。

例: フラッシュセール中は、過剰販売を避けるために在庫数量が削減されます。

テーブル `tb_goods_stock` を作成します (
 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
 `goods_id` bigint(20) unsigned DEFAULT '0' COMMENT '商品ID',
 `nums` int(11) unsigned DEFAULT '0' COMMENT '製品在庫数',
 `create_time` datetime DEFAULT NULL COMMENT '作成時刻',
 `modify_time` datetime DEFAULT NULL COMMENT '更新時間',
 主キー (`id`)、
 ユニークキー `goods_id` (`goods_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='製品在庫テーブル';

データベース レベルで負の数が発生しないように、製品在庫数量の数値フィールド タイプを unsigned に設定します。

悲観的ロックを使用するには、MySQL の自動コミット機能をオフにして、autocommit = 0 を設定する必要があることに注意してください。

MySQL の行レベルのロックはインデックスに基づいていることに注意してください。SQL がインデックスを使用しない場合、テーブル全体のロックにはテーブルレベルのロックが使用されます。

1. トランザクションを開始し、販売する製品を照会し、レコードをロックします。

始める;
更新のために、goods_id = {$goods_id} である tb_goods_stock から数値を選択します。

2. 商品の数量が購入数量より多いかどうかを判断します。満足できない場合は、トランザクションをロールバックします。

3. 条件が満たされた場合は、在庫を減らしてトランザクションをコミットします。

tb_goods_stock を更新し、nums = nums - {$num} を設定します。 
ここで、goods_id = {$goods_id} かつ nums >= {$num} です。
専念;

トランザクション中に保持されたロックは、トランザクションがコミットされると解除されます。

悲観的ロックは、最初にロックしてから同時実行制御でデータを処理するという保守的な戦略を採用しています。データ処理のセキュリティは確保されますが、効率も低下します。

2. 楽観的ロック

名前が示すように、これはデータ処理に対して楽観的な姿勢を取り、データが一般的に競合しないという楽観的な考えを持つことを意味します。データの更新を送信するときにのみ、データの競合が検出されます。

競合が見つかった場合は、エラー メッセージがユーザーに返され、ユーザーは続行方法を決定できます。

楽観的ロックの実装は、データベースが提供するロック メカニズムに依存せず、自分で実装する必要があります。実装方法は一般的にデータ バージョンを記録するもので、1 つはバージョン番号によるもので、もう 1 つはタイムスタンプによるものです。

テーブルにバージョン番号またはタイムスタンプフィールドを追加します。データを読み取るときは、バージョン番号も一緒に読み取ります。データが更新されると、バージョン番号が 1 増加します。

データの更新を送信するときに、現在のバージョン番号が最初に読み取られたバージョン番号と等しいかどうかを判断します。等しい場合は更新されます。等しくない場合は、データは期限切れとみなされ、更新は拒否され、ユーザーは再度操作する必要があります。

テーブル `tb_goods_stock` を作成します (
 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
 `goods_id` bigint(20) unsigned DEFAULT '0' COMMENT '商品ID',
 `nums` int(11) unsigned DEFAULT '0' COMMENT '製品在庫数',
 `create_time` datetime DEFAULT NULL COMMENT '作成時刻',
 `modify_time` datetime DEFAULT NULL COMMENT '更新時間',
 `version` bigint(20) unsigned DEFAULT '0' COMMENT 'バージョン番号',
 主キー (`id`)、
 ユニークキー `goods_id` (`goods_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='製品在庫テーブル';

1. 販売する製品を照会し、バージョン番号を取得します。

始める;
tb_goods_stock から、goods_id = {$goods_id} である nums、version を選択します。

2. 商品の数量が購入数量より多いかどうかを判断します。満足できない場合は、トランザクションをロールバックします。

3. 条件が満たされた場合は、在庫を削減します。 (アップデートの際は、現在のバージョンが手順1で取得したバージョンと同じかどうかを確認してください)

tb_goods_stock を更新し、nums = nums - {$num}、version = version + 1 に設定します。 
ここで、goods_id = {$goods_id} 
version = {$version} かつ nums >= {$num};

4. 更新操作が正常に実行されたかどうかを判断します。成功した場合はコミットし、そうでない場合はロールバックします。

楽観的ロックはプログラムに基づいて実装されるため、デッドロックが発生せず、読み取りが多いアプリケーションのシナリオに適しています。競合が頻繁に発生すると、上位アプリケーションがユーザーに再操作を要求し続けることになり、パフォーマンスが低下します。この場合は、悲観的ロックがより適しています。

MySQL 関連のコンテンツにさらに興味がある読者は、次のトピックを確認してください: 「MySQL データベース ロック関連スキルの概要」、「MySQL ストアド プロシージャ スキルの概要」、「MySQL 共通関数の概要」、「MySQL ログ操作スキルの概要」、および「MySQL トランザクション操作スキルの概要」。

この記事が皆様のMySQLデータベース設計に役立つことを願っています。

以下もご興味があるかもしれません:
  • MySQL における楽観的ロックと悲観的ロックの例
  • MySQL の悲観的ロックと楽観的ロックの使用例
  • MySQL における楽観的ロック、悲観的ロック、MVCC の包括的な分析
  • MySQL における悲観的ロックと楽観的ロック
  • MySQL 悲観的ロックと楽観的ロックの実装

<<:  iptables の再起動後に Docker の iptables ルールの完全なプロセスが失われる

>>:  Vueを使用して天気コンポーネントをロードする方法の詳細な説明

推薦する

CSSは、他のレイヤーを変更せずに、多層ネスト構造の最外層を回転させる効果を実現します。

次のようなシナリオがあります。円形のコンテナで、最も外側のコンテナの背景が円弧になっています。内側の...

MySQL は制限を使用してページング例メソッドを実装します

1. 制限の基本的な実装一般的に、クライアントは、pageNo (ページ番号) と pageSize...

ウォーターフォールフローレイアウト(無限読み込み)を実現する js

この記事の例では、ウォーターフォールフローレイアウトを実装するためのjsの具体的なコードを参考までに...

ドラッグ可能なログインボックスを実現するネイティブJS

この記事では、ネイティブ JS で実装されたドラッグ可能なログイン ボックスを紹介します。その効果は...

デザインリファレンス 美しく独創的なブログデザイン

以下にリストされているすべてのブログはオリジナルであり、独自にデザインされています。これらは、他者が...

MySQLデータベース設計:Pythonを使ったスキーマ操作方法の詳しい解説

矢が放たれる前に、弓は矢にささやきました。「お前の自由は私のものだ。」スキーマは矢のようなもので、弓...

JavaScript の 3 つの BOM オブジェクト

目次1. 場所オブジェクト1. URL 2. 場所オブジェクトのプロパティ3. ロケーションオブジェ...

互換性を維持しながら他のウェブページのデータを適用する iframe の使い方

以下は、Shiji Tiancheng が Tencent KartRider ページを呼び出すため...

HTML ページでコンテンツの選択、コピー、右クリックを防止する方法の詳細な説明

時には、Web ページに掲載されているコンテンツが悪意のある人物に盗用されるのを望まないため、Web...

Dockerのインストール方法とDockerの4つのネットワークモードの詳細説明

1. Dockerをインストールするyum -y install docker-ioインストールが完...

テーブルレイアウトの長所と短所、そして推奨されない理由

テーブルの欠点1. テーブルは他の HTML タグよりも多くのバイトを占有します。 (ダウンロード時...

MySql ページングで limit+order by を使用する場合のデータ重複の解決策

目次まとめ問題の説明問題を分析する問題を解決するまとめ複雑な知識をシンプルに説明できることは重要です...

ウェブページを作成する際に注意すべき点

--ホームページのバックアップ1.txtテキスト2. 画像をスキャンする3. PSDデザイン原画(A...

フォームの送信イベントが応答しない

1. 問題の説明<br />JS を使用してフォームの送信メソッドを呼び出してフォームを...

Linux環境でグラフデータベースneo4jを構築する方法の説明

Neo4j (Nosql の 1 つ) は、高性能なグラフ データベース (分散をサポートしていませ...