MySQL,Perl DBI,execute()和锁定(锁定的确切时刻)



我正在开发Perl/DBI/DBD/MySQL应用程序。我正在使用具有事务级别"可重复读取"和"自动提交= 0"的InnoDB。为了保护我正在操作的数据免受其他线程或连接的并发操作,我使用以下模式(这很常见):

$h_DB -> do("START TRANSACTION");
$s_SQL = "SELECT data from Users where ID = ? FOR UPDATE";
$h_ST = $h_DB -> prepare($s_SQL);
$h_ST -> execute($s_ID);
# Do some other stuff
@ar_Row = $h_ST -> fetchrow_array();
# Do data manipulation
$h_DB -> do("COMMIT")

为了清楚起见,我省略了错误处理和变量声明,但我认为变量名称是不言自明的。

我的问题是:锁(在本例中为:排他锁)究竟何时放在相应的行上?它们是否在执行运行后就位,或者它们是否在读取行后不早于活动状态?换句话说,在指定的"#做一些其他事情"部分中,锁是否已经就位?

通常,通过使用MySQL命令行工具进行一些研究,很容易回答这些问题。但在这种情况下,我认为这是不可能的,原因如下:

1)我不确定MySQL客户端的行为是否与Perl的DBI/DBD完全一样。

2)当然,上面的例子非常简化。实际上,我想知道使用上述模式时何时设置锁,但一次锁定数百行,即与 WHERE 子句匹配的数百行。

我认为我无法使用命令行客户端来找出答案,因为对于大型数据集,可能存在缓冲,Perl 和命令行客户端可能会以不同的方式处理,并且我怀疑我是否可以"模拟"已在 Perl 中执行的语句,但其结果行尚未获取, 通过在命令行客户端中使用类似"LIMIT 0"的内容。

有人能给出明确的答案吗?

$s_SQL ="从用户中选择数据,其中 ID = ?更新";

执行此操作将尝试获取受影响行的锁

,然后获取数据(或等到它获得所有受影响行的独占锁)。这样做是为了线程安全,并且只返回已经锁定的数据:这样就可以保证服务器返回任何其他客户端/线程都无法修改的最新数据。

这些行将被锁定,直到提交或回滚。

MySQL cli客户端中的行为与锁定在服务器中完成而不是在客户端库中完成的行为相同。

这仅适用于MySQL InnoDB表。像MyISAM这样的其他引擎的行为有所不同。

而不是

$h_DB->do("START TRANSACTION");
...
$h_DB->do("COMMIT");

您可能应该调用DBI方法

$h_DB->begin_work;
...
$h_DB->commit;

唯一的区别是,您在自己的代码中对数据库驱动程序的行为进行事后猜测,同时降低其可移植性。DBI调用依赖于驱动程序知道如何启动和停止此数据库的事务,并且是正确的方法

数据库

事务的本质是事务中的所有内容都将不受任何并行数据库连接的干扰。有些数据库只会在事务期间锁定整个数据库,但大多数数据库会更加优化,并允许在事务进行时从任何地方读取和写入不相关的表

带有 FOR UPDATE 限定符的SELECT的含义是,您请求在读取开始时启动事务,并且无需自己显式打开事务。获得值后,它们将不会更改,数据库中影响它们的任何其他内容也不会更改。需要访问已锁定数据的连接将被暂停,除非它们要求脏功能

这涵盖了所有内容吗?

相关内容

  • 没有找到相关文章

最新更新