有没有办法保证MySQL中的非阻塞读取?

时间:2009-10-25 00:12:11

标签: sql mysql

我已经尝试了明显的“SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED”,但我的简单存储过程在更新正在进行的同时在PRIMARY KEY上执行SELECT MAX时仍然被阻止(当与某些复杂的更新事务同时运行时我不想修改) - 最终遇到死锁和锁定超时。

当然必须有一种方法来保证非阻塞读取......而且我认为这是READ-UNCOMMITTED的目的。但我错了......这是一个MySQL错误吗?有解决办法吗?

我知道READ-UNCOMMITTED的所有危险和学术上不健全的属性,但这无关紧要,对于我的特定应用程序偶尔会出现幻影或丢失行,这里确实没什么大不了的,但是延迟或错误由读锁引起的是一个更严重的问题。

数据库中的所有表都是InnoDB。 服务器版本是5.0.67。平台是Linux 32位。

更新 以下是问题描述的简化“hello world”版本(我的实际查询过于复杂且难以发布):

控制台1:

mysql> create table t1(a int primary key) engine=innodb;
Query OK, 0 rows affected (0.20 sec)

mysql> insert into t1 values (1),(2),(3);
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values (4);
Query OK, 1 row affected (0.01 sec)

mysql> update t1 set a=5 where a=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

CONSOLE 2(在单独的窗口中,不要关闭CONSOLE 1)

mysql> select max(a) from t1;
+--------+
| max(a) |
+--------+
|      3 | 
+--------+
1 row in set (0.00 sec)

mysql> set @test = (select max(a) from t1);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

3 个答案:

答案 0 :(得分:4)

终于明白了:

“这是MySQL的错误吗?” - >是的,我称之为bug。其他人可能称之为限制或“陷阱”。我称之为BUG,因为很明显,理论基础以及在没有锁定的情况下检索这些数据的实际能力可以通过大多数语法解决方法来证明。

“有解决方法吗?” - >是。

重写此

set @test = (select max(a) from t1);

这个

select max(a) from t1 into @test;
当另一个事务没有运行时,

产生相同的结果;并且当另一个事务正在运行时,产生预期的结果(成功立即检索值,而不是死锁)。

答案 1 :(得分:1)

如果你想确定你的选择永远不会阻止你的更新,那么我建议你有两个数据库,其中master是插入/更新的地方,通过复制,数据被发送到slave,在哪里做选择。

这应该限制选择中的任何问题,因为复制速度非常快,因此您的选择可能会像您想要的那样复杂,并且它永远不会影响更新。

不幸的是,即使您只是进行了行锁定,您仍可能会遇到问题,因为一个查询在尝试从该表读取时正在写入表。

更新:在您投票之前,他最近提出了查询和错误消息,所以现在他可以帮助解决问题,所以我的回答没有错,因为他开始时

答案 2 :(得分:0)

默认情况下,InnoDB SELECT通常是非锁定的(这样它们可以运行尽可能多的DML语句)。所以它似乎不仅仅是普通的SELECT和DML语句。

也许你正在做一个INSERT ... SELECT语句或类似的东西?你可以发布你的存储过程吗?