MySQL、Perl DBI、execute() 和锁定(锁定的精确时刻)

MySQL, Perl DBI, execute() and locking (exact moment of locking)

我正在开发 Perl/DBI/DBD/MySQL 应用程序。我正在使用事务级别 "repeatable read" 和 "autocommit = 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")

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

我的问题是:锁(在本例中为独占锁)到底是什么时候放在相应行上的?它们是在执行 运行 之后就已经就位了,还是在获取行之后就处于活动状态?换句话说,锁定是否已经在指定的“# Do some other stuff”部分中就位?

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

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

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

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

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

$s_SQL = "SELECT data from Users where ID = ? FOR UPDATE";

执行此操作将尝试获取受影响行的锁,然后获取数据(或等待直到获得所有受影响行的独占锁)。这样做是为了线程安全,并且只有 return 已经锁定的数据:这样可以保证服务器 returns 的最新数据不能被任何其他 [=19] 修改=].

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

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

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

而不是

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

您可能应该调用 DBI 方法

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

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

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

SELECTFOR UPDATE 限定符的含义是您要求在读取开始时启动事务,而无需自己显式打开事务。一旦你获得了这些值,它们就不会被改变,数据库中的任何其他影响它们的东西也不会改变。需要访问您已锁定的数据的连接将被挂起,除非他们请求 脏读 功能

这涵盖了所有内容吗?