← Назад к вопросам

Какой уровень изоляции предотвращает Dirty Write?

2.7 Senior🔥 141 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Уровни изоляции транзакций и Dirty Write

Dirty Write — это явление, когда одна транзакция перезаписывает данные, которые ещё не были закоммичены другой транзакцией. Это одна из самых опасных аномалий в многопользовательских СУБД.

Что такое Dirty Write?

Транзакция 1 выполняет WRITE x = 100, потом Транзакция 2 выполняет WRITE x = 200 (грязная запись). Затем Транзакция 1 выполняет ROLLBACK, и x возвращается к прежнему значению. Но Транзакция 2 уже закоммитила значение 100, а не 200.

Уровни изоляции ACID

SQL стандарт определяет четыре уровня изоляции. Dirty Write предотвращается на ВСЕ уровнях, начиная с самого слабого:

1. READ UNCOMMITTED

// Может прочитать грязные (незакоммиченные) данные
statement.execute("UPDATE accounts SET balance = 500 WHERE id = 1");
ResultSet rs = statement.executeQuery("SELECT balance FROM accounts WHERE id = 1");

Допускает Dirty Read и Non-Repeatable Read, но Dirty Write предотвращается.

2. READ COMMITTED

Connection conn = DriverManager.getConnection(url, user, pass);
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

Предотвращает Dirty Write и Dirty Read. Это стандартный уровень в PostgreSQL.

3. REPEATABLE READ

conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);

Предотвращает Dirty Write, Dirty Read и Non-Repeatable Read. Допускает Phantom Read.

4. SERIALIZABLE

conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

Предотвращает все аномалии, включая Phantom Read. Максимальная безопасность, минимальная производительность.

Почему Dirty Write предотвращается везде?

Базовая проблема Dirty Write — это конфликт записи-записи (Write-Write conflict). Все СУБД решают это через Write Locks на уровне ядра:

Transaction 1: LOCK X → WRITE X = 100
Transaction 2: LOCK X (waiting...) → WAIT
Transaction 1: COMMIT, UNLOCK X
Transaction 2: LOCK X (success)WRITE X = 200 → COMMIT

Поэтому даже на READ UNCOMMITTED две транзакции не могут одновременно писать в один и тот же объект.

Сравнительная таблица аномалий

УровеньDirty ReadNon-Rep ReadPhantom Read
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

Практический пример

public class TransactionDemo {
    public static void main(String[] args) throws SQLException {
        Connection conn = DriverManager.getConnection(url);
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
        
        try {
            conn.setAutoCommit(false);
            Statement stmt = conn.createStatement();
            stmt.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1");
            stmt.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2");
            conn.commit(); // Грязная запись невозможна
        } catch (SQLException e) {
            conn.rollback();
        } finally {
            conn.close();
        }
    }
}

Ответ

Dirty Write предотвращается на ВСЕ уровнях изоляции, включая READ UNCOMMITTED. Это происходит благодаря Write Locks на уровне ядра СУБД, которые не позволяют двум транзакциям одновременно модифицировать один и тот же объект.