これは説明が難しい (そして非常に奇妙である) ので、我慢してください。問題とその修正について説明しますが、なぜそれが機能するのかを誰かが説明できるかどうかを確認したいと思います:)
mod_perl を使用する Web アプリケーションがあります。MySQL データベースを使用しており、定期的にデータベースにデータを書き込んでいます。これはモジュール式であるため、独自の「データベース」タイプのモジュールもあり、接続や更新などを処理します。database::db_connect() サブルーチンはデータベースへの接続に使用されAutoCommit
、0 に設定されます。
データベースから定期的にデータを取得し、返されるデータに応じてさまざまなタスクを実行する、別の Perl アプリケーション (スタンドアロン デーモン) を作成しました。そこに database.pm モジュールを含めているので、すべてを書き直したり複製したりする必要はありません。
私が経験している問題は次のとおりです。
アプリケーションは起動時にデータベースに接続し、無限にループして、X 秒ごとにデータベースからデータを取得します。ただし、データベース内のデータが更新された場合でも、データベースへの最初の接続/クエリで取得した「古い」データがアプリケーションに返されます。
たとえば、3 つの行があり、列「名前」には各レコードの値「a」、「b」、および「c」があります。行の 1 つを更新し (たとえば、コマンド ラインから mysql クライアントを使用)、名前を「c」から「x」に変更すると、スタンドアロン デーモンはそのデータを取得しません。 MySQL。tcpdump で db トラフィックをキャプチャしたところ、MySQL が実際にそのデータを返していることがはっきりとわかりました。SELECT で SQL_NO_CACHE を使用しようとしましたが (何が起こっているのかわからなかったので)、どちらも役に立ちませんでした。
次に、スタンドアロン デーモンで DB 接続文字列を変更し、AutoCommit
1 に設定しました。突然、アプリケーションが適切なデータを取得し始めました。
AutoCommit は INSERT/UPDATE タイプのステートメントにのみ影響し、SELECT ステートメントには影響しないと思っていたので、私は困惑しています。しかし、それは一見そうです、そして私はその理由を理解していません。
AutoCommit
が0 に設定されている場合に SELECT ステートメントがデータベースから「更新された」行を返さない理由と、AutoCommit
が 1 に設定されている場合に更新された行を返す理由を知っている人はいますか?
これは、スタンドアロンデーモンで使用している単純化された (エラーチェックなどを取り除いた) コードであり、更新された行を返しません。
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use Data::Dumper;
$|=1;
my $dsn = "dbi:mysql:database=mp;mysql_read_default_file=/etc/mysql/database.cnf";
my $dbh = DBI->connect($dsn, undef, undef, {RaiseError => 0, AutoCommit => 0});
$dbh->{mysql_enable_utf8} = 1;
while(1)
{
my $sql = "SELECT * FROM queue";
my $stb = $dbh->prepare($sql);
my $ret_hashref = $dbh->selectall_hashref($sql, "ID");
print Dumper($ret_hashref);
sleep(30);
}
exit;
1 に変更AutoCommit
すると、これが修正されます。なんで?
ありがとう :)
PS: 誰が気にするかわかりませんが、DBI バージョンは 1.613、DBD::mysql は 4.017、perl は 5.10.1 (Ubuntu 10.04) です。