Уровень чтения Commited Isolation не работает - PullRequest
0 голосов
/ 03 мая 2020

Я пытаюсь понять принцип изоляции ACID. Я кодировал эту часть кода:

ExecutorService executorService = Executors.newSingleThreadExecutor();

        Runnable t2 = () -> {
            System.out.println("Thread: " + Thread.currentThread().getName());
            Connection connection;

            try {
                connection = this.iDatabaseConnector.getConnection();

                PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM mssmbank.mssmbank.bankaccounts WHERE id = ?");
                preparedStatement.setInt(1, 490);

                ResultSet resultSet = preparedStatement.executeQuery();
                resultSet.next();

                System.out.println("Result: " + resultSet.getDouble("BALANCE"));

                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        };

        Runnable t1 = () -> {
            System.out.println("Thread: " + Thread.currentThread().getName());
            Connection connection;

            try {
                connection = this.iDatabaseConnector.getConnection();
                connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
                connection.setAutoCommit(false);

                PreparedStatement preparedStatement = connection.prepareStatement("UPDATE mssmbank.mssmbank.bankaccounts " + "SET balance = ? WHERE id = ?");
                preparedStatement.setDouble(1, (new Random()).nextInt(1000));
                preparedStatement.setInt(2, 490);
                preparedStatement.executeUpdate();

                ExecutorService executorService1 = Executors.newSingleThreadExecutor();
                executorService1.execute(t2);

                Thread.sleep(3_000);

                connection.commit();
                connection.close();

                executorService1.shutdown();
                executorService1.awaitTermination(20, TimeUnit.SECONDS);
            } catch (SQLException | InterruptedException e) {
                e.printStackTrace();
            }
        };

        executorService.execute(t1);
        executorService.shutdown();
        executorService.awaitTermination(20, TimeUnit.SECONDS);

Есть 2 потока, t1 и t2 . t1 должен обновить строку банковского счета в базе данных, а t2 должен прочитать свой баланс.

Вот сценарий: t1 запустить, открыть соединение, сделать обновление и не зафиксировать . Он запускает t2 и спит в течение 3 секунд.

t2 запускает, открывает соединение, считывает баланс и печатает его (в основном старый один, потому что t1 еще не зафиксирован), затем закройте соединение.

Затем t1 завершится к , совершив обновление, и программа завершится.

Я ожидаю, что t2 будет заблокирован до тех пор, пока t1 не завершит фиксацию, поскольку t2 получает доступ к тому же банковскому счету. строка ( t1 должна была заблокировать строку для обновления). Поэтому t2 должен был печатать обновленный баланс банковского счета # 490, а не предыдущий.

Почему t1 не блокирует строку? почему t2 не блокируется? Обратите внимание, что Уровень изоляции установлен на TRANSACTION_READ_COMMITTED.

1 Ответ

1 голос
/ 03 мая 2020

Оператор выбора в t2 не блокируется, потому что он только пытается читать, а не писать. Если вы попытаетесь выполнить обновление (или выберите ... для обновления), то он может заблокироваться, если для вашего тайм-аута задано время ожидания в течение некоторого периода времени, прежде чем сдаться. Вы не упоминаете, какую базу данных вы используете, но вот несколько хороших документов о том, как Postgres обрабатывает блокировку: https://www.postgresql.org/docs/current/explicit-locking.html

...