为什么SELECT FOR UPDATE仅在事务中起作用?

时间:2014-04-03 18:51:54

标签: mysql perl transactions locking innodb

我认为我对SELECT FOR UPDATE构造感到困惑 示例:

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";  

即脚本在第二个会话未阻止的事务中运行! 如果脚本在事务中运行,为什么它只阻止

1 个答案:

答案 0 :(得分:9)

根据documentation

  

使用SELECT FOR UPDATE锁定行以进行更新仅适用于禁用自动提交时(通过使用START TRANSACTION开始事务或将自动提交设置为0.如果启用了自动提交,则与规范不匹配的行不会锁定。

换句话说,如果您未在交易中执行第一个SELECT FOR UPDATE,则不会锁定任何行。