Java 允许这种行为吗?

Java 允许这种行为吗?,java,mysql,jdbc,innodb,isolation-level,Java,Mysql,Jdbc,Innodb,Isolation Level,我设置了两个JDBC连接到一个正在测试的MySQL数据库,并且正在使用InnoDB。 连接以不同的隔离级别启动事务,我测试哪些修改对哪个连接可见,然后执行哪些操作: public static void main(String args[]) { final Connection con1 = DriverManager.getConnection(url, user, passwd); con1.setTransactionIsolation(Connection.TRANS

我设置了两个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);");
}
我总是以空表开始运行代码。我得到的输出是

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
已经提交。为什么会这样?在给定的隔离级别下,我期望的行为合法吗?据我所知,我正在创建的读取现象是幻象读取,因此这对于
可重复读取
,应该没问题,对吧?

我的解释是,一旦您读取了数据,后续读取的事务将是相同的

如果您等待运行
countRows(con2)
直到
con1.commit()
之后,您将看到
1
,因为它还没有被读取

我不认为在这种情况下会发生任何现象,我认为这正是
REPEATABLE\u READ
的行为。在事务中读取数据后,可以重复读取相同的数据


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

尝试在
addRow(con1)
之后再运行
countRows(con2)
,看看是否得到不同的结果(即上次读取
countRows(con2)
得到
1
@Alex的结果在这种情况下
con2
确实看到了
con1
插入的新行。但是为什么我的代码没有在隔离级别
REPEATABLE\u READ
中创建幻影读取?哦,我明白了。谢谢。我不知道InnoDB使用了比ACID更严格的
REPEATABLE\u READ
定义e、 ACID的隔离级别
REPEATABLE\u READ
允许幻象读取,如果两个相同的查询在同一事务中返回不同的行,则会发生幻象读取。这就是我的代码所做的:它插入一个新行,以便第一个计数行看到
0
行,并在提交后看到(应该)请参阅
1
行。但InnoDB限制了
可重复读取的要求,这是我问题的答案。谢谢:)