Видимость изменений внутри одной транзакции - PullRequest
0 голосов
/ 21 мая 2018

Я работаю с JDBC в режиме setAutoCommit(false).

Внутри одной транзакции я выполняю несколько операторов для вставки, обновления и выбора.

Вопрос : должны ли эти изменения быть видимыми внутри той же транзакции для последующих операций?Какие конкретные правила существуют?Это зависит от производителя?Это зависит от драйвера?Или как?

Я работаю с mysql-connector-java 8.0.11, JDBC 4.2, java 8 и в моем случае никаких изменений не видно , например

  try (Connection conn = dataSource.getConnection()) {
            conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            conn.setAutoCommit(false);
            try (PreparedStatement statement = conn.prepareStatement(sqlInsert, PreparedStatement.RETURN_GENERATED_KEYS)) {
                statement.setString(1, "testData");
                statement.executeUpdate();
                System.out.println("After insertion:");
                // jdbc findAll impl.
                findAll().forEach(System.out::println);
                conn.commit();
            } catch (SQLException ex) {
                conn.rollback();
            }
        } catch (SQLException e) {
            throw new RuntimeException();
        }

Здесь вставленные незафиксированные данные на самом деле НЕ видны внутри одной и той же транзакции!

Однако, если я сделаю то же самое с jdbcTemplate Spring и DataSourceTransactionManager Spring, например:

final DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();

defaultTransactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
TransactionStatus transaction = txManager.getTransaction(defaultTransactionDefinition);

try {
    // jdbcTemplate insert impl.
    insert("testData");
    System.out.println("After insertion:");
    // jdbcTemplate findAll impl.
    findAll().forEach(System.out::println);
    txManager.commit(transaction);
} catch (Exception e) {
    txManager.rollback(transaction);
}

Вставленныйнезафиксированные данные фактически видны внутри той же транзакции!

Я не нашел объяснений в спецификации JDBC, и смущен им.

Пожалуйста, объясните это поведение.

PS Яосведомлены о разных уровнях изоляции, но в основном они применяются к параллельным транзакциям, а не к одной и той же.

1 Ответ

0 голосов
/ 22 мая 2018

Поскольку в ваших комментариях содержится дополнительная информация о том, что findAll создает новое соединение, проблема заключается в том, что вы используете одно соединение + транзакция для обновления данных и другое соединение + транзакция для выбора данных.

На запрос выбора влияет транзакция: транзакция определяет, является ли видимым или нет.У вас есть соединение 1 с транзакцией 1, где вы изменили данные (еще не зафиксировано), и соединение 2 с транзакцией 2, которая выполняет выбор.Поскольку транзакция 1 еще не зафиксирована, транзакция 2 не может увидеть данные, измененные транзакцией 1.

Если вы используете JdbcTemplate и диспетчер транзакций Spring, все изменится, потому что Spring выполняет дополнительную работу, чтобы гарантировать, что он используетодно и то же соединение и транзакция как для обновления, так и для выбора.

...