2015-01-26 2 views
1

Я устанавливаю два подключения JDBC к базе данных тестирования MySQL и использую InnoDB. Соединения начать операции в различных уровнях изоляции, и я проверить, какие изменения могут видеть, какое соединение, после чего действия:Возможно ли поведение MySQL?

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, правильно?

+0

Попробуйте * не * запустить 'countRows (con2)' до появления 'addRow (con1)' и посмотреть, получится ли вам другой результат (т. Е. Последнее чтение 'countRows (con2)' получает результат '1' – Alex

+0

@Alex В этом случае 'con2' видит новую строку, вставленную' con1'. Но почему мой код не создает _phantom reads_ на уровне изоляции 'REPEATABLE_READ'? – MinecraftShamrock

ответ

3

Моя интерпретация http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_repeatable-read такова, что когда вы прочитали данные, то это будет то же самое для этой операции для последующего чтения

Если вы ждали, чтобы запустить countRows(con2) только после con1.commit() то вы не увидите 1, поскольку она hasn еще не прочитано

Не думаю, что есть явление происходит в этом сценарии, я думаю, что это точное поведение REPEATABLE_READ. После того, как данные были прочитаны в транзакции, это повторяемо, прочитайте то же самое

Почему вы думаете, что видите странное явление?

+0

О, я вижу. Спасибо. Я не знал, InnoDB использует более строгое определение 'REPEATABLE_READ', чем требуется ACID. Уровень изоляции ACID' REPEATABLE_READ' позволяет делать фантомные чтения, которые возникают, если два идентичных запроса возвращают разные строки в одной транзакции. Это то, что делает мой код: он вставляет новую строку так что первые строки count видят строки '0', а после commit (должен) видеть строку' 1'. Но InnoDB ограничивает требования 'REPEATABLE_READ', что является ответом на мой вопрос. Спасибо :) – MinecraftShamrock

Смежные вопросы