Mysql 为什么SELECT FOR UPDATE仅在事务中起作用?
我想我对这个结构感到困惑。Mysql 为什么SELECT FOR UPDATE仅在事务中起作用?,mysql,perl,transactions,locking,innodb,Mysql,Perl,Transactions,Locking,Innodb,我想我对这个结构感到困惑。 例如: mysql> select * from employees2; +-------+----------+--------+-----------+ | EmpId | EmpName | DeptId | EmpSalary | +-------+----------+--------+-----------+ | 1 | John | 1 | 5000.00 | | 2 | Albert
例如:
mysql> select * from employees2;
+-------+----------+--------+-----------+
| EmpId | EmpName | DeptId | EmpSalary |
+-------+----------+--------+-----------+
| 1 | John | 1 | 5000.00 |
| 2 | Albert | 1 | 4500.00 |
| 3 | Crain | 2 | 6000.00 |
| 4 | Micheal | 2 | 5000.00 |
| 5 | David | NULL | 34.00 |
| 6 | Kelly | NULL | 457.00 |
| 7 | Rudy | 1 | 879.00 |
| 8 | Smith | 2 | 7878.00 |
| 9 | Karsen | 5 | 878.00 |
| 10 | Stringer | 5 | 345.00 |
| 11 | Cheryl | NULL | NULL |
+-------+----------+--------+-----------+
11 rows in set (0.00 sec)
我在脚本中执行以下操作:
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect('dbi:mysql:testdb','root','1234', {'RaiseError' => 1, 'AutoCommit' => 0}) or die "Connection Error: $DBI::errstr\n";
my $sql = "select * from employees2 where EmpId IN (2,10) for update";
my $sth = $dbh->prepare($sql);
$sth->execute or die "SQL Error: $DBI::errstr\n";
while (my @row = $sth->fetchrow_array) {
print "@row\n";
}
sleep(9000);
$dbh->commit;
我还可以并行使用控制台并连接到数据库。因此,我首先运行脚本,然后在另一个会话中执行以下操作:
mysql> select * from employees2 where EmpId IN (10) for update;
第二个选择块指的是同一行。这将阻止我执行以下操作:
mysql> set autocommit = 0;
mysql> begin;
mysql> select * from employees2 where EmpId IN (10) for update;
mysql> commit;
或者只是
mysql> select * from employees2 where EmpId IN (10) for update;
因此,如果它在事务中或不在事务中,它将阻止不相关的操作。现在,如果我将脚本更改为:
my $dbh = DBI->connect('dbi:mysql:practice','root','') or die "Connection Error: $DBI::errstr\n";
也就是说,脚本不会在第二个会话未阻止的事务中运行如果脚本在事务中运行,为什么它只阻止 仅当禁用自动提交时(通过使用
START transaction
开始事务或将autocommit设置为0),使用SELECT for update
锁定要更新的行。如果启用了autocommit,则与规范匹配的行不会被锁定
换句话说,如果您没有在事务中执行第一个
SELECT FOR UPDATE
,则不会锁定任何行。要回答您的新问题:SELECT…FOR UPDATE
仅锁定行,直到您提交执行它的事务。autocommit
在默认情况下处于启用状态,因此当您没有明确禁用时在这种情况下,您执行的每个SQL语句都形成一个单独的事务(即使用InnoDB)。换句话说,您的第一个SELECT…FOR UPDATE
将被执行,然后立即提交,释放锁。@ThisSuitesBlacknot:啊,是的!将其作为答案发布,我会接受。我的评论有点偏离…至少对于MySQL 5.5,如果您在事务中不执行SELECT FOR UPDATE
,则不会锁定hap笔(与我在评论中所说的锁定、立即提交和释放锁定相反)。顺便问一下,您是否发现了最初发布的问题,即您在in
子句中未包含的行上看到锁?@ThisSuitesBlacknot:是的。原因是表没有定义主键。如果它是单个查询,但for update是update查询的子查询的一部分,该怎么办假设查询只有一个,并且不在事务中,但我想它应该可以工作,因为提交只在update语句之后完成。它是具有for update语句的select子查询的父查询