PHPでのお話です。
マスター/スレーブまでカバーしたDBライブラリを使用しているときに、なぜかSELECTしたあとTRUNCATE文を発行したら、なぜか永遠に処理が終わらないという現象に遭遇しました。
SELECTはスレーブに接続して、INSERT,UPDATE,DELETEはマスターに接続するという単純なライブラリです。
まあちょっと事情があってライブラリのソースは公開できないんですが、クエリーログ的には以下のような感じです。
1
2
3
4
5
6
7
8
9
|
Connect root@localhost on test
Connect root@localhost on test
Query begin
Prepare SELECT name FROM `test` WHERE name IN ( ?,?)
Execute SELECT name FROM `test` WHERE name IN ( 'abc','deg')
Close stmt
Query commit
Query begin
Query TRUNCATE TABLE test
|
つまり、testテーブルにSELECTしたあと、TRUNCATEしたわけですね。
で、一見クエリー的には最後にcommitされない現象いがいは至って普通なわけです。
クエリー的には本当に普通なんですが、コード的にはちょっと微妙な感じです。
だいたいこんな感じです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<?php
$config = array(
'type' => 'mysql',
'host' => 'localhost',
'database' => 'test',
'user' => 'root',
'password' => 'root'
);
$mysqli = new mysqli($config['host'],$config['user'],$config['password'],$config['database']);
$mysqli2 = new mysqli($config['host'],$config['user'],$config['password'],$config['database']);
$mysqli2->query('begin');
$stmt = $mysqli->prepare("SELECT name FROM `test` WHERE name IN ( ?,?)");
if ( $stmt->errno ) {
exit("error");
}
$a = "abc";
$b = "deg";
$stmt->bind_param('ss',$a,$b);
if ( $stmt->errno ) {
echo "error";
exit;
}
$stmt->execute();
$stmt->close();
unset($stmt);
$mysqli2->query('commit');
$mysqli2->query('begin');
$mysqli2->query("TRUNCATE TABLE test");
$mysqli2->query('commit');
|
問題なのは$mysqliでSELECTのクエリ実行する前に$mysqli2でbeginしているところ。
これが非常に問題なのですが、まあ既存のライブラリを僕が使ってただけなので僕は(ry
ってことはどうでもいいんですが、以下のクエリをちゃんとマスター/スレーブ分割した環境で使用するならある程度は問題なく実行できるんですが、開発環境等で、スレーブ設定めんどくさくてスレーブ接続先もマスターにしてしまうってことがあるかと思います。
そこまで原因を完璧には把握していませんが、どうやら二つ接続しているのとMySQLサーバ側のプリペアドステートメントを利用していることが原因で、TRUNCATE文で詰まってしまうんだと思います。
ほかの言語だとどんな感じか今度試してみます。
ちなみにmysqlのautocommitの値は0になっています。
追記
他の言語で検証しました。
MySQLdbでTRUNCATE TABLE文を発行したら、commitされなかったでござるの巻き