トップへ(mam-mam.net/)

MariaDB / MySQL トランザクション分離レベル(transaction-isolation)の解説と設定方法

MariaDB / MySQL トランザクション分離レベル(transaction-isolation)の解説と設定方法

MariaDB / MySQLのトランザクション分離レベル(transaction-isolation)は、複数のトランザクションが同時に実行される際のデータ整合性を制御する重要な仕組みです。
本記事では、各分離レベルの特徴(READ UNCOMMITTED / READ COMMITTED / REPEATABLE READ / SERIALIZABLE)と、ダーティリード・非再現読取・ファントムリードといった代表的な問題を整理。
さらに、my.cnfでの設定例やPHP(PDO)での実装例も紹介します。

トランザクション分離レベルで問題となる現象

ダーティリード(Dirty Read) 「未コミットの変更を読んでしまう問題」
他のトランザクションが「未だコミットしていない変更」を読み取ってしまうこと。
(例)以下の②はまだコミットされていない値を読んで矛盾が生じている
①トランザクションAが、ある行をUPDATEで更新したが、未だCOMMITしていない。
②トランザクションBが、その変更後の値を読み取る。
③トランザクションAがROLLBACKする。
非再現読取 (Non-Repeatable Read) 「同じ行を読んでも結果が変わる問題」
同じトランザクション内で「同じ条件のクエリを複数回実行」したときに取得結果(値)が変わること。
(例)以下のトランザクションAの①③で読み取った値が変わっている
①トランザクションAがある行をSELECTして読む。
②トランザクションBがその行をUPDATEしてCOMMITする。
③トランザクションAが再度同じ行をSELECTして読むと①と値が変わっている。
ファントムリード (Phantom Read) 「同じ条件検索でも行数が変わる問題」
同じトランザクション内で同じ条件の検索を複数回行ったときに取得行数が増減すること。
(例)
①トランザクションAが「年齢>30」の条件でSELECT実行し10行の結果を得る。
②トランザクションBが新たに「年齢>30」のレコードを1件だけINSERTしてコミットする。
③トランザクションAが再度同じ条件「年齢>30」でSELECTすると11件の結果になる。
分離レベル
transaction-isolationの値
ダーティリード 非再現読取 ファントムリード
READ-UNCOMMITTED ○(発生する) ○(発生する) ○(発生する)
READ-COMMITTED
(更新系システムでよく使われる)
×(防止できる) ○(発生する) ○(発生する)
REPEATABLE-READ
(MySQLのデフォルト)
×(防止できる) ×(防止できる) ○(発生する)
SERIALIZABLE
(完全保証が必要な特殊ケース)
×(防止できる) ×(防止できる) ×(防止できる)

○:発生する可能性あり ×:防止できる

my.cnf 設定例

[mysqld]
transaction-isolation = READ-UNCOMMITTED
[mysqld]
transaction-isolation = READ-COMMITTED
[mysqld]
transaction-isolation = REPEATABLE-READ
[mysqld]
transaction-isolation = SERIALIZABLE

PHP(PDO)での設定例

$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'user', 'password');

// 分離レベルを READ UNCOMMITTED に設定
$pdo->exec("SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");

// 分離レベルを READ COMMITTED に設定
$pdo->exec("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED");

// 分離レベルを REPEATABLE READ に設定
$pdo->exec("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ");

// 分離レベルを SERIALIZABLE に設定
$pdo->exec("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE");
MariaDB(MySQL)のサンプルSQL一覧に戻る