🐬

MySQLで同時編集を防ぐ方法

に公開

MySQLで同時編集を防ぐ方法

MySQLで同時編集(同時更新)を防ぐには、排他制御を導入します。排他制御には主に以下の2つの方法があります。


1. 悲観的排他制御(ペシミスティックロック)

  • データを更新する際、最初にロックを取得し、更新が終わるまで他のユーザーが同じデータを編集できないようにします。
  • 具体的には、トランザクション内で SELECT ... FOR UPDATE などのSQLを使い、対象行をロックします。
  • 衝突が多い場合や、確実に競合を防ぎたい場合に有効です。

2. 楽観的排他制御(オプティミスティックロック)

  • データ取得時にはロックをかけず、更新時に「他のユーザーによって変更されていないか」を確認します。
  • 例えば、レコードに「バージョン番号」や「タイムスタンプ」カラムを設け、更新時に値が変わっていなければ更新、変わっていればエラーとする方法です。
  • 衝突が少ない場合や、更新頻度が低い場合に向いています。

3. アドバイザリロック(アプリケーションロック)

  • MySQLの GET_LOCK()RELEASE_LOCK() 関数を使い、アプリケーションレベルでロックを実現する方法もあります。
  • これは、特定のレコードや処理単位で「名前付きロック」を取得し、他のセッションが同じ名前のロックを取得できないようにします。

4. ロック管理用テーブルを使う方法

  • 編集開始時に「ロック管理テーブル」に情報を書き込み、他ユーザーが同じレコードを編集しようとした際に「編集中」と表示して編集を制限する方法もあります。
  • 離脱時のロック解除やタイムアウト処理も設計する必要があります。

代表的なSQL例

悲観的排他制御(行ロック)

START TRANSACTION;
SELECT * FROM reservations WHERE id = 1 FOR UPDATE;
-- 編集・更新処理
COMMIT;

楽観的排他制御(バージョンカラム利用)

UPDATE reservations
SET time = '10:00', version = version + 1
WHERE id = 1 AND version = 5;
-- 影響行数が0なら他ユーザーが先に更新している

アドバイザリロック

SELECT GET_LOCK('reservation_1', 10);
-- 編集・更新処理
SELECT RELEASE_LOCK('reservation_1');

まとめ

  • 悲観的排他制御:ロックを使い、同時更新を物理的に防ぐ
  • 楽観的排他制御:バージョンやタイムスタンプで衝突検知
  • アドバイザリロックGET_LOCK() などでアプリケーションレベルのロック
  • ロック管理テーブル:DBテーブルで編集状態を管理

運用状況やシステム要件に応じて、これらの方法を選択・組み合わせてください。

Discussion