隔离级别为READ_UNCOMMITTED时,无法查看正在运行的事务所插入的行

时间:2014-06-17 06:33:39

标签: mysql transactions isolation-level read-uncommitted

我有应用程序同时在表 A 中插入行。每个应用程序使用每个批处理的单个事务以批处理模式(使用JDBC预准备语句)插入行(以避免在每个INSERT之后重建索引)。每个批次中存在的行完全独立,该事务仅用于优化。每个插入的行都会自动设置其主键(AUTO_INCREMENT)。

我有另一个应用程序根据其ID处理表A中的行。应用程序流程范围为[ID1,ID2],然后处理范围[ID2+1,ID3][ID3+1,ID4]等。每个范围,例如[ID1,ID2]可能包含在不同事务期间插入的行,并且可能尚未提交其中某些事务。例如,在范围[ID1,ID2]中,在尚未提交的事务期间可能已插入行[ID1,ID1+N],而在已提交的事务期间可能已插入行[ID1+N+1,ID2]。 因此,在选择范围[ID1,ID2]中的行时,事务隔离级别设置为READ_UNCOMMITTED,以便可以看到未提交的行。

问题在于,有时,未提交的行不可见,因此永远不会被处理。

SELECT之后很短的时间内执行INSERT时,似乎会出现此问题。我做了一个测试,其中一个连接在作为事务包装的批处理中插入多个行,并且在提交事务之前,等待一段时间后,另一个连接查询具有READ_UNCOMMITTED的行作为事务隔离级别,并且行是可见的。因此,我得出结论,即使插入了一行并释放了自动增量计数器锁,尽管READ_UNCOMMITTED被设置为事务隔离级别,但该行可能对其他事务不可见。

1 个答案:

答案 0 :(得分:0)

如果我从另一个控制台登录,使用我的小测试脚本在提交之前不会显示任何记录。不过,我可以在同一个会话中选择刚刚插入的记录。所以我假设在提交之前你可以访问已经存在于表中的行,但现在可以在提交之前访问新行或更改。

<?php

require_once('db.php');

q( 'drop table if exists t' );
q( 'create table t (id integer not null auto_increment primary key, v datetime) engine=innodb' );

q( 'set transaction isolation level read uncommitted' );
q( 'start transaction' );
q( 'insert into t (v) values (now()),(now()),(now())' );

echo q1( 'count(*)', 't', 'true'); // translates to "select count(*) from t where true"; 
// echoes "3" to the console

// wait for input
$handle = fopen ("php://stdin","r");
$line = fgets($handle);

// with a mysql client from a 2nd console at this point no new records show in table t

q( 'commit' );

// after this point all new records show up in table t from a 2nd session.