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を使用して天気コンポーネントをロードする方法の詳細な説明

推薦する

MySQLはライブラリ内の主キーなしでテーブルインスタンスコードを素早く取得します

概要MySQL データベースで主キーのないテーブルを表示するための SQL ステートメントをいくつか...

MySql ファジークエリ JSON キーワード取得ソリューションの例

目次序文オプション1:オプション2:オプション3:オプション4(最終的に採用されたオプション):要約...

MySQLスタートアップが起こした事故の実録

目次背景MySQLが完全に起動したかどうかを確認する方法事故最初の変更2回目の改訂要約するMySQL...

MySQL 5.7.18 インストーラーのインストール ダウンロード グラフィック チュートリアル

この記事では、MySQL 5.7.18インストーラーの詳細なインストールチュートリアルを参考までに記...

Dockerイメージ解析ツールのダイブ原理解析

今日は、Docker イメージ、各レイヤーの内容を調べ、Docker/OCI イメージのサイズを縮小...

リフレッシュリダイレクトを実現する HTML ヘッドタグメタ

コードをコピーコードは次のとおりです。 <html> <ヘッド> <m...

HTML で div+CSS を使用してシンプルな矢印アイコンを実装するコード

ウェブデザインでは、ウェブページを美しく見せるために矢印を装飾としてよく使用します。現在、多くのウェ...

一般的な docker コマンドの概要 (推奨)

1. 要約:一般的に、次のカテゴリに分類できます。 Docker 環境情報 — docker [i...

MySQLクエリ最適化プロセスを理解する

目次パーサーとプリプロセッサクエリオプティマイザーMySQL クエリの最適化には、解析、前処理、最適...

Dockerでイメージ情報を表示する方法

この記事では、Dockerでイメージ情報を表示する方法を学ぶ必要があります。 1. imagesコマ...

Windows Server 2016 に Docker をインストールする方法

最近、Microsoft は Docker をネイティブにサポートする Windows Server...

Linux で open-vswitch をインストールおよびアンインストールする方法

1. ソースコードからovsをコンパイルしてインストールします。依存関係をインストールします: # ...

js を使用して USB スキャナー データを取得する方法

この記事では、USBバーコードスキャナデータを取得するjsの具体的なプロセスを参考までに紹介します。...

Vue はアップロードされた画像に透かしを追加する機能を実装します

この記事では、Vueでアップロードされた画像に透かしを追加する具体的な実装コードを参考までに共有しま...

DockerはRedisをインストールし、操作用のビジュアルクライアントを導入します

1 はじめにRedis 、 ANSI C言語で開発されたKey-Valueベースの高性能NoSQLデ...