这种 MySQL 行为是否被允许?
Is this MySQL behavior allowed?
我设置了两个 JDBC 连接到测试 MySQL 数据库,并且正在使用 InnoDB。
连接以不同的隔离级别启动事务,我测试哪些修改对哪个连接可见,然后执行哪些操作:
public static void main(String args[]) {
final Connection con1 = DriverManager.getConnection(url, user, passwd);
con1.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
con1.setAutoCommit(false);
final Connection con2 = DriverManager.getConnection(url, user, passwd);
con2.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
con2.setAutoCommit(false);
System.out.println(countRows(con1));
System.out.println(countRows(con2));
addRow(con1);
System.out.println(countRows(con1));
System.out.println(countRows(con2));
con1.commit();
System.out.println(countRows(con1));
System.out.println(countRows(con2));
}
使用这些辅助方法:
public static int countRows(final Connection c) throws Exception {
final Statement s = c.createStatement();
final ResultSet rs = s.executeQuery("SELECT * FROM test;");
int count = 0;
while(rs.next()) {
count++;
}
rs.close();
s.close();
return count;
}
public static void addRow(final Connection c) throws Exception {
final Statement s = c.createStatement();
s.executeUpdate("INSERT INTO test (user, age) VALUES ('Guy', 42);");
}
我 运行 代码总是以空 table 开头。我得到的输出是
0 //initially no rows for both connections
0
1 //con1 adds row
0 //con2 does not see uncommitted new row
1
0 //con1 has committed => Why isn't the new row visible?
我希望最后一个数字是 1,因为 con1
此时已经提交。为什么会这样?对于给定的隔离级别,我期望的行为是否合法?据我了解,我正在创建的读取现象是幻读,所以 REPEATABLE_READ
应该没问题吧?
我对 http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read 的解释是,一旦您读取了数据,后续读取的该事务将是相同的
如果你等到 运行 countRows(con2)
直到 con1.commit()
之后你会看到 1
因为它还没有被阅读
我认为在这种情况下不会发生任何 现象,我认为这正是 REPEATABLE_READ
的行为。在事务中读取数据后,将重复读取相同的数据
为什么您认为自己看到了奇怪的现象?
我设置了两个 JDBC 连接到测试 MySQL 数据库,并且正在使用 InnoDB。 连接以不同的隔离级别启动事务,我测试哪些修改对哪个连接可见,然后执行哪些操作:
public static void main(String args[]) {
final Connection con1 = DriverManager.getConnection(url, user, passwd);
con1.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
con1.setAutoCommit(false);
final Connection con2 = DriverManager.getConnection(url, user, passwd);
con2.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
con2.setAutoCommit(false);
System.out.println(countRows(con1));
System.out.println(countRows(con2));
addRow(con1);
System.out.println(countRows(con1));
System.out.println(countRows(con2));
con1.commit();
System.out.println(countRows(con1));
System.out.println(countRows(con2));
}
使用这些辅助方法:
public static int countRows(final Connection c) throws Exception {
final Statement s = c.createStatement();
final ResultSet rs = s.executeQuery("SELECT * FROM test;");
int count = 0;
while(rs.next()) {
count++;
}
rs.close();
s.close();
return count;
}
public static void addRow(final Connection c) throws Exception {
final Statement s = c.createStatement();
s.executeUpdate("INSERT INTO test (user, age) VALUES ('Guy', 42);");
}
我 运行 代码总是以空 table 开头。我得到的输出是
0 //initially no rows for both connections
0
1 //con1 adds row
0 //con2 does not see uncommitted new row
1
0 //con1 has committed => Why isn't the new row visible?
我希望最后一个数字是 1,因为 con1
此时已经提交。为什么会这样?对于给定的隔离级别,我期望的行为是否合法?据我了解,我正在创建的读取现象是幻读,所以 REPEATABLE_READ
应该没问题吧?
我对 http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read 的解释是,一旦您读取了数据,后续读取的该事务将是相同的
如果你等到 运行 countRows(con2)
直到 con1.commit()
之后你会看到 1
因为它还没有被阅读
我认为在这种情况下不会发生任何 现象,我认为这正是 REPEATABLE_READ
的行为。在事务中读取数据后,将重复读取相同的数据
为什么您认为自己看到了奇怪的现象?