2017-02-10 41 views
1

我已经写了'phantom read'的代码,如果隔离级别不可序列化,我的代码应该打印不同的值,但是我有'可重复读取'隔离级别,它的工作原理类似于可序列化。它显示了我相同的数字,但应该第二次显示更大的数字。为什么这样?我有MySql数据库。这里我的例子:为什么'可重复读'隔离级别在Java中把我从'幻影读取'中拯救出来?

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 doc https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html只能从'幻影读取'保存。那么为什么从'phanotom read'保存可重复的读取水平?

+0

可怕袋熊 - 重复的读取处理重复读取,serialisable处理幻读https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html –

+0

看到http://stackoverflow.com/a/11044968/2310289 –

回答

1

MySQL docs从(大约REPEATABLE READ):在同一事务中

一致读取读取由第一读取建立的快照 。

Consistent reads

甲读使用快照信息基于在时间点呈现查询结果 ,而不管由 同时运行的其他事务执行的改变的操作。

当您设置自动提交到false这意味着两个select都在同一个事务中执行。那么,你的担忧是什么?看起来像它预期的那样工作。

还要注意this remark:

假设你是在默认的REPEATABLE READ隔离 级别运行。当您发出一致的读取(即普通SELECT 声明)时,InnoDB会根据您的查询查看数据库的 为您的事务提供一个时间点。如果另一个事务删除 行并在分配时间点后提交,则看不到 行已被删除。插入和更新的处理方式相似。

+0

我同意这样做** **我期望,但因为他们是不同的'连接',那么我会认为他们是不同的tranactions。根据[链接](http://stackoverflow.com/a/11044968/2310289)*发生幻像读取时,在事务过程中,执行两个相同的查询,并且第二个查询返回的行集合不同于第一个。* –

+1

它们绝对是不同的交易。关于这种影响所说的一切都属于不同交易的情况。当你使用具体的RDMS时,最好依靠这个DB文档而不是通用的JDBC描述,因为最终的行为由DB决定。 – Andremoniy

+0

'REPEATABLE READ' *可以具有幻影行并不一定意味着它必须具有幻影行。 InnoDB next-key/gap locks可能是这里的一个因素。 https://dev.mysql.com/doc/refman/5.7/en/innodb-next-key-locking.html我同意这个答案,观察到的行为不一定是错误的。 –