[MariaDB]カレントリード
公開日:2026-01-15
更新日:2026-01-15
更新日:2026-01-15
1. 概要
分離レベルが REPEATABLE READ(デフォルト)の場合でも、
innodb_snapshot_isolation を OFF にして、
SELECT に LOCK IN SHARE MODE や FOR UPDATE を付けると、
他のトランザクションで変更された内容を含む最新の値を取得します。
デフォルトでは innodb_snapshot_isolation は ON になっており、
SELECT ~ FOR UPDATE をした時に、スナップショット作成時からレコードが変更されている場合は、エラーが発生します。
(エラー:ERROR 1020 (HY000): Record has changed since last read in table 'products')
次のコマンドで innodb_snapshot_isolation の設定・取得が行えます。
innodb_snapshot_isolation を OFF にして、
SELECT に LOCK IN SHARE MODE や FOR UPDATE を付けると、
他のトランザクションで変更された内容を含む最新の値を取得します。
デフォルトでは innodb_snapshot_isolation は ON になっており、
SELECT ~ FOR UPDATE をした時に、スナップショット作成時からレコードが変更されている場合は、エラーが発生します。
(エラー:ERROR 1020 (HY000): Record has changed since last read in table 'products')
次のコマンドで innodb_snapshot_isolation の設定・取得が行えます。
コマンド
# 設定
SET SESSION innodb_snapshot_isolation = ON; # ERROR 1020 エラーが出るようにチェックを厳しくする
# 取得
SHOW SESSION VARIABLES LIKE 'innodb_snapshot_isolation';2. 動作確認
2.1 テストデータ
テストデータは、「排他ロック・共有ロック」で作成したものを使用します。
テストデータの作成
テストデータの作成
コマンド
CREATE DATABASE test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE products (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255),
price INTEGER,
stock INTEGER DEFAULT 0,
PRIMARY KEY (id)
);
INSERT INTO products (id, name, price, stock) VALUES (1, 'A', 1000, 10), (2, 'B', 2000, 20), (3, 'C', 3000, 30);2.2 他のトランザクションの変更によりエラーが発生するケース(デフォルトの動作)
スナップショットとDBの最新の値(SELECT ~ FOR UPDATE で取得する値)が異なるため、エラーが発生する。
AとBは異なるトランザクション
AとBは異なるトランザクション
コマンド
# 初期設定
UPDATE products SET stock = 10 where id = 1;
SET SESSION innodb_snapshot_isolation = ON; # ERROR 1020 エラーが出るようにチェックを厳しくする
A:BEGIN;
B:BEGIN;
B:SELECT stock FROM products where id = 1; # スナップショットが作成される
A:UPDATE products SET stock = 999 where id = 1;
B:SELECT stock FROM products where id = 1; # stock:10(スナップショットの値)
B:SELECT stock FROM products where id = 1 FOR UPDATE; # 待機。Aのコミット後、ERROR 1020 が発生する
A:COMMIT;
B:COMMIT;2.3 FOR UPDATE の有無で検索結果が変わるケース(innodb_snapshot_isolation が OFF が場合)
コマンド
# 初期設定
UPDATE products SET stock = 10 where id = 1;
SET SESSION innodb_snapshot_isolation = OFF; # ERROR 1020 エラーが出ないようにする。チェックを緩くする
A:BEGIN;
B:BEGIN;
B:SELECT stock FROM products where id = 1; # スナップショットが作成される
A:UPDATE products SET stock = 999 where id = 1;
B:SELECT stock FROM products where id = 1 FOR UPDATE; # 待機。Aのコミット後、stock:999(最新の値)が返る
A:COMMIT;
B:SELECT stock FROM products where id = 1; # stock:10(スナップショットの値)
B:SELECT stock FROM products where id = 1 FOR UPDATE; # stock:999(最新の値)
B:COMMIT;2.4 UPDATE で他のトランザクションの変更によりエラーが発生するケース
stock がスナップショット作成後に変更されているため、UPDATE がエラーになる。
UPDATE 前に SELECT をしていなければ、UPDATE 時がスナップショットになるため、エラーにならない。
UPDATE 前に SELECT をしていなければ、UPDATE 時がスナップショットになるため、エラーにならない。
コマンド
# 初期設定
UPDATE products SET stock = 10 where id = 1;
SET SESSION innodb_snapshot_isolation = ON; # ERROR 1020 エラーが出るようにチェックを厳しくする
A:BEGIN;
B:BEGIN;
B:SELECT stock FROM products where id = 1; # スナップショットが作成される
A:UPDATE products SET stock = 999 where id = 1;
A:COMMIT;
B:UPDATE products SET stock = stock - 1 where id = 1 and stock - 1 > 0; # ERROR 1020 が発生する
B:ROLLBACK;
