mysql – DBI数据库句柄与AutoCommit设置为0不能使用SELECT返回正确的数据?

这是一个棘手的解释(很奇怪),所以忍受我.我会解释这个问题,并解决它,但我想看看是否有人可以解释为什么它的工作原理:)

我有一个使用mod_perl的Web应用程序.它使用MySQL数据库,我正在定期向数据库写入数据.它是模块化的,因此它还具有自己的“数据库”类型的模块,其中我处理连接,更新等.database :: db_connect()子例程用于连接到数据库,AutoCommit设置为0.

我创建了另一个Perl应用程序(独立守护程序),它定期从数据库中获取数据,并根据返回的数据执行各种任务.我在其中包含database.pm模块,所以我不必重写/复制一切.

我遇到的问题是:

应用程序在启动时连接到数据库,然后永远循环,每X秒从数据库中提取数据.但是,如果数据库中的数据被更新,我的应用程序仍然被返回“旧”数据,我得到了初始连接/查询数据库.

例如 – 我有3行,列“名称”对于每个记录都有值’a’,’b’和’c’.如果我更新其中一行(例如使用命令行中的mysql客户端),并将Name从’c’更改为’x’,则我的独立守护程序将无法获取该数据 – 它仍然会从/ MySQL的.我用tcpdump捕获了数据库流量,我可以肯定地看到MySQL真的返回了这些数据.我已经尝试使用SQL_NO_CACHE与SELECT(因为我不知道发生了什么),但这也没有帮助.

然后,我修改了我的独立守护进程中的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;

将AutoCommit更改为1可修复此问题.为什么?

谢谢 :)

P.S:不知道是否有人关心,但DBI版本是1.613,DBD :: mysql是4.017,perl是5.10.1(在Ubuntu 10.04上).

最佳答案
我想你使用的是InnoDB表,而不是MyISAM表.如InnoDB transaction model中所述,您的所有查询(包括SELECT)都在事务中进行.

当AutoCommit打开时,每个查询都会启动事务,如果成功,则会隐式提交事务(如果失败,行为可能会有所不同,但事务将保证结束).您可以在MySQL的binlog中看到隐式提交.通过将AutoCommit设置为false,您需要自行管理事务.

默认事务隔离级别为REPEATABLE READ,这意味着所有SELECT查询将读取相同的快照(事务启动时创建的快照).

除了在另一个答案中给出的解决方案(ROLLBACK之前开始阅读)这里有几个解决方案:

您可以选择另一个事务隔离级别,如READ COMMITTED,这使您的SELECT查询每次都读取新的快照.

您也可以将AutoCommit设置为true(默认设置),并通过发出BEGIN WORK开始您自己的交易.这将暂时禁用AutoCommit行为,直到您发出COMMIT或ROLLBACK语句,之后每个查询再次获取自己的事务(或者您通过BEGIN WORK启动另一个事务).

我个人会选择后一种方法,因为它似乎更优雅.

转载注明原文:mysql – DBI数据库句柄与AutoCommit设置为0不能使用SELECT返回正确的数据? - 代码日志