Как изменить уровень изоляции транзакций в JDBC?

Ответ

Уровень изоляции транзакций в JDBC задается с помощью метода Connection.setTransactionIsolation(int level). Этот метод необходимо вызывать до начала транзакции (перед setAutoCommit(false) или любой операцией, изменяющей данные).

Доступные уровни изоляции (константы интерфейса Connection):

  1. TRANSACTION_READ_UNCOMMITTED — самое слабое. Допускает грязное чтение (Dirty Read), неповторяемое чтение (Non-repeatable Read) и фантомное чтение (Phantom Read).
  2. TRANSACTION_READ_COMMITTED — стандартный уровень для многих СУБД (например, PostgreSQL, Oracle). Предотвращает грязное чтение.
  3. TRANSACTION_REPEATABLE_READ — предотвращает грязное и неповторяемое чтение. Используется в MySQL по умолчанию (InnoDB).
  4. TRANSACTION_SERIALIZABLE — самое строгое. Полная изоляция, транзакции выполняются последовательно.
  5. TRANSACTION_NONE — транзакции не поддерживаются (редко используется).

Пример установки уровня READ_COMMITTED:

Connection conn = dataSource.getConnection();
// Установка уровня ДО начала транзакции
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
conn.setAutoCommit(false);
// ... выполнение операций
conn.commit();

Важные замечания:

  • Поддерживаемые уровни зависят от конкретной СУБД и драйвера JDBC. Не все уровни могут быть доступны.
  • Уровень изоляции можно проверить с помощью Connection.getTransactionIsolation().
  • Повышение уровня изоляции увеличивает корректность данных, но снижает производительность из-за более строгого блокирования.

Ответ 18+ 🔞

Давай разберём эту тему про уровни изоляции, а то тут, блядь, такой пиздец творится, что волосы дыбом встают! Представь, два потока лезут в одну базу, как два алкаша в последнюю бутылку — без правил начнётся драка, данные порвут, всё просрут.

В JDBC, чтобы такого пиздопроёбища не случилось, есть штука под названием Connection.setTransactionIsolation(int level). Запомни раз и нахуй: вызывать этот метод надо до того, как ты начнёшь транзакцию! То есть перед setAutoCommit(false) или первой же операцией, которая данные трогает. Иначе будет как в том анекдоте: «после драки кулаками не машут».

Доступные уровни, они как круги ада — от лёгкого пиздеца до полного дзена, но за дзен надо платить скоростью.

Смотри, какие константы в интерфейсе Connection есть:

  1. TRANSACTION_READ_UNCOMMITTED — это, ёпта, полный бардак. Один поток пишет, даже не закоммитившись, а второй уже это дерьмо читает. Грязное чтение (Dirty Read), неповторяемое, фантомы — всё в одном флаконе, как дешёвый самогон. Только для отчаянных, кому похуй на целостность.
  2. TRANSACTION_READ_COMMITTED — нормальный, адекватный уровень. Как в приличном обществе: пока не положил в карман (не закоммитил), никто твои деньги не видит. Грязное чтение отсекает. Его многие СУБД, типа PostgreSQL или Oracle, по умолчанию используют. Работает, не грузит сильно.
  3. TRANSACTION_REPEATABLE_READ — тут уже серьёзнее. Обещает, что если ты в транзакции дважды прочитал одну запись, то получишь одно и то же. То есть от соседней транзакции тебе не прилетит неожиданное изменение прямо под носом. В MySQL (InnoDB) это дефолт, между прочим.
  4. TRANSACTION_SERIALIZABLE — это, блядь, железный занавес. Полная изоляция, будто транзакции выполняются строго по очереди, одна за другой. Никаких фантомов, никаких сюрпризов. Но и производительность, ядрёна вошь, может накрыться медным тазом, потому что блокировок овердохуища.
  5. TRANSACTION_NONE — а это вообще пидарас шерстяной, транзакций нет. Редкая хуйня, лучше даже не смотреть в эту сторону.

Вот как это в коде выглядит, смотри:

Connection conn = dataSource.getConnection();
// Установка уровня ДО начала транзакции, блядь! Не проеби момент!
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
conn.setAutoCommit(false);
// ... выполнение операций
conn.commit();

И главное, на что внимание обратить, а то подозрение ебать чувствую:

  • Поддержка уровней — это на совести СУБД и драйвера. Может оказаться, что твоя база какой-то уровень просто игнорит, выпендривается.
  • Текущий уровень можно спросить через Connection.getTransactionIsolation() — проверить, не обманули ли тебя.
  • И помни золотое правило: чем строже изоляция, тем надёжнее, но и тем медленнее всё будет. Выбирай по обстановке, не гонись за SERIALIZABLE, если можно обойтись READ_COMMITTED. Иначе получишь правильные, но охуенно медленные данные, и все пользователи разбегутся, блядь.