9cubed
ブログ | Tailwind | Vite | Python | MariaDB | Node.js | Linux | PowerShell | Docker | Git | その他 | 将棋ウォーズ | 歌の練習
< 前の記事

論理削除(ソフトデリート)

次の記事 >

テーブル結合(CROSS JOIN、INNER JOIN、LEFT JOIN)

MariaDB

[MariaDB]楽観ロック・悲観ロック

公開日:2026-01-16
更新日:2026-01-16

1. 概要

排他制御の楽観ロック・悲観ロックについてです。
楽観ロックは「他の人が同時に同じデータを更新することは滅多にないだろう。もしそんなことがあったら逆立ちして町内を一周してやるよ。」と言う楽観的な考えで作られた排他制御で、
悲観ロックは「他の人が同時に同じデータを更新することがあるはずだ。もしそんなことされたら二度と立ち直れない。」と言う悲観的な考えで作られた排他制御です。

2. 使用する場所

悲観ロック:競合が許されない処理(決済、予約、在庫変更など)
楽観ロック:Web アプリの入力画面~更新処理
楽観ロック+リトライ:競合が許されない処理

3. 楽観ロック

テーブルに version を持たせて、入力画面に入った時に取得した version と、更新処理時の version を比較して、値が異なる場合は、誰かに変更されていると判断する方式です。

3.1 データベースとテーブル

コマンド
CREATE DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    version INT DEFAULT 0 NOT NULL  
);

INSERT INTO users (name, email) VALUES ('taro', 'taro@example.com');

3.2 処理の流れ

入力画面に入った時に version を取得して、hidden などに入れます。
コマンド
SELECT name, email, version FROM users WHERE ID = 1;

更新ボタンが押されたら、hidden などで保持していた verion を更新条件に入れて、更新します。
コマンド
UPDATE users
SET email = 'taro2@example.com', version = version + 1
WHERE ID = 1 AND version = { hidden で保持していた version }

影響行数が 1 件の場合は、正常に更新されています。
影響行数が 0 件の場合は、更新失敗です。他の人によって変更されていることをユーザに通知してエラーにします。

入力画面に入ってから、入力に時間がかかる場合は、競合の確率が高くなります。
その場合、編集ユーザID(locked_by)と編集開始時刻(locked_at)をテーブルに保持して、入力画面に入った時に、他のユーザが編集中であることを通知したり、
入力画面の中で定期的に WebAPI で version を取得して、変更されている場合は、他のユーザに変更されたことを通知します。

4. 悲観ロック

排他ロックをかけて、他のトランザクションからは同時に変更できないようにする方式です。

4.1 処理の流れ

コマンド
BEGIN;

# 排他ロック
SELECT 在庫数 FROM 在庫テーブル WHERE ID = 1 FOR UPDATE;

if (在庫数 - 注文数 < 0) {
    エラーにする
}

# 更新
UPDATE 在庫テーブル SET 在庫数 = 在庫数 - 注文数 WHERE ID = 1;

# コミット
COMMIT;

競合すると他のトランザクションはブロックされて待機するため、競合の確率が高い場合は、パフォーマンスが悪くなります。

ちなみに、上記の在庫を減らすだけの場合は、悲観ロック(事前にロック)にせずに、UPDATE の条件を追加することで、SQL の数を減らせます。
コマンド
BEGIN;

# 更新
UPDATE 在庫テーブル SET 在庫数 = 在庫数 - 注文数 WHERE ID = 1 AND 在庫数 - 注文数 > 0;

影響行数が 0 の場合は、在庫不足のためエラーにする

# コミット
COMMIT;
< 前の記事

論理削除(ソフトデリート)

次の記事 >

テーブル結合(CROSS JOIN、INNER JOIN、LEFT JOIN)

YouTube X

新着一覧

  • テーブル結合(CROSS JOIN、INNER JOIN、LEFT JOIN)MariaDB
  • 楽観ロック・悲観ロックMariaDB
  • カレントリードMariaDB
  • インデックスMariaDB
  • 論理削除(ソフトデリート)MariaDB
  • awk(オーク)の使い方についてLinux
  • NOT NULL 制約と NULL を許容した時の動作MariaDB
  • 外部キー制約MariaDB
  • MySQL と MariaDB の関係MariaDB
  • Docker で PostgreSQL のコンテナの使用Linux

アーカイブ

  • 2026/01
  • 2025/12
  • 2025/11
  • 2025/10
  • 2025/09
  • 2025/08
  • /00

以前のカテゴリー一覧

  • CakePHP3
  • CentOS7
  • HTML・CSS・JavaScript
  • Haskell
  • JavaScript
  • Kotlin
  • Laravel5
  • PHP
  • Python
  • Ruby
  • RubyOnRails5
  • TypeScript
  • Vue.js
  • Webサーバ講座
  • Webプログラミング講座
  • jQuery
  • linux
  • パソコン講座
  • ブログ
  • プログラミング講座
  • メモ帳作成講座
  • 数学

Copyright © 9cubed. All Rights Reserved.

プライバシーポリシー 利用規約
▲