是否允许这种MySQL行为?

时间:2015-01-26 17:43:16

标签: java mysql jdbc innodb isolation-level

我为测试MySQL数据库设置了两个JDBC连接,并使用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);");
}

我总是以空表开始运行代码。我得到的输出是

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应该没问题,对吧?

1 个答案:

答案 0 :(得分:3)

我对http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read的解释是这样的,一旦你读完了数据,后续读取的那个事务就会相同

如果您等到countRows(con2)之后才等con1.commit(),那么您会看到1,因为它还没有被阅读

我不认为在这种情况下有任何现象,我认为这是REPEATABLE_READ的确切行为。一旦在事务中读取了数据,就可以重复读取相同的

为什么你认为你看到一个奇怪的现象?