java - 为什么 java 中的 'Repeatable read' 隔离级别将我从 'Phantom reads' 中拯救出来?

标签 java mysql jdbc isolation-level

我编写了带有“幻读”的代码,如果隔离级别不可序列化,我的代码应该打印不同的值,但我有“可重复读取”隔离级别,它的工作方式类似于可序列化。它显示相同的数字,但第二次应该显示更大的数字。为什么这样?我有 MySql 数据库。这是我的例子:

public class PhantomReadLesson {
static String url = "jdbc:mysql://localhost:3306/Lessons";
static String username = "root";
static String password = "1";
public static void main(String[] args) throws SQLException, InterruptedException {
    try(Connection conn = DriverManager.getConnection(url, username, password);
        Statement statement = conn.createStatement()) {
        conn.setAutoCommit(false);
        conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
        ResultSet rs = statement.executeQuery("Select count(*) from Books");
        while(rs.next()){
            System.out.println(rs.getInt(1));
        }
        new OtherTransaction2().start();
        Thread.currentThread().sleep(1000);
        rs = statement.executeQuery("Select count(*) from Books");
        while(rs.next()){
            System.out.println(rs.getString(1));
        }
    }
}

static class OtherTransaction2 extends Thread {
    @Override
    public void run() {
        try(Connection conn = DriverManager.getConnection(url, username, password);
            Statement stmt = conn.createStatement()) {
            conn.setAutoCommit(false);
            conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            stmt.executeUpdate("insert into Books (name) VALUES ('new Row')");
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
}

我在这里模仿“幻读”。如果我使用“repeatable_read”或“serializable”级别,它会显示相同的数字,如果使用“read_commmited”或“read_uncomited”级别,它将显示不同的数字。但根据 java 文档 https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html只能从“幻读”中进行序列化保存。那么为什么可重复读取级别从“phanotom 读取”中保存?

最佳答案

来自 MySQL docs (关于REPEATABLE READ):

Consistent reads within the same transaction read the snapshot established by the first read.

Consistent reads :

A read operation that uses snapshot information to present query results based on a point in time, regardless of changes performed by other transactions running at the same time.

当您将自动提交设置为 false 时,这意味着两个选择都在同一事务中执行。那么,你有什么顾虑?它看起来像预期的那样工作。

另请注意this remark:

Suppose that you are running in the default REPEATABLE READ isolation level. When you issue a consistent read (that is, an ordinary SELECT statement), InnoDB gives your transaction a timepoint according to which your query sees the database. If another transaction deletes a row and commits after your timepoint was assigned, you do not see the row as having been deleted. Inserts and updates are treated similarly.

关于java - 为什么 java 中的 'Repeatable read' 隔离级别将我从 'Phantom reads' 中拯救出来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42149604/

相关文章:

mysql - Unicode 字符保存不正确

jdbc - 在ibatis中获取批量插入/更新的更新计数

mysql - 使用多个连接 sql 查找多个计数

java - Spring:使用 2 个子句进行派生查询?

java - android项目中的project.properties

Java 等于原始速度与对象速度

php - 计算表中的出现次数并打印计数和排名

MySQL 选取所有30天未登录的用户

Mac OS High Sierra 上的 Java 驱动程序 Firebird 2.5

java - Spring的值注释在构造函数参数中不起作用