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

Что такое COMMIT в SQL?

1.3 Junior🔥 171 комментариев
#Базы данных и SQL

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

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

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

Что такое COMMIT в SQL

COMMIT — это SQL команда, которая фиксирует все изменения в базе данных, произведённые в текущей транзакции. После выполнения COMMIT все операции становятся постоянными и видны другим пользователям/приложениям.

Понятие транзакции

Транзакция — это логическая единица работы, состоящая из одной или нескольких SQL команд (INSERT, UPDATE, DELETE). Транзакция либо полностью выполняется, либо полностью откатывается. Это принцип ACID (Atomicity, Consistency, Isolation, Durability).

START TRANSACTION;  -- Начало транзакции (неявно в большинстве БД)

UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

COMMIT;  -- Фиксируем обе операции

Если происходит сбой после UPDATE первого счёта, но до COMMIT, обе операции будут откачены (отменены).

Как это работает в JDBC

При работе с Java и БД через JDBC:

Connection conn = DriverManager.getConnection(url, user, password);

try {
    // По умолчанию autoCommit = true
    conn.setAutoCommit(false);  // Отключаем автоматический коммит
    
    Statement stmt = conn.createStatement();
    stmt.executeUpdate("UPDATE accounts SET balance = 900 WHERE id = 1");
    stmt.executeUpdate("UPDATE accounts SET balance = 1100 WHERE id = 2");
    
    conn.commit();  // Фиксируем обе операции
    System.out.println("Transaction committed successfully");
} catch (SQLException e) {
    conn.rollback();  // Откатываем все операции при ошибке
    System.err.println("Transaction rolled back: " + e.getMessage());
} finally {
    conn.close();
}

COMMIT vs ROLLBACK

COMMIT — фиксирует изменения:

BEGIN;
UPDATE accounts SET balance = 900 WHERE id = 1;
COMMIT;  -- Изменение теперь постоянно в БД

ROLLBACK — отменяет все изменения транзакции:

BEGIN;
UPDATE accounts SET balance = 900 WHERE id = 1;
ROLLBACK;  -- Вернёмся к состоянию до BEGIN

Состояния транзакции

Actual work
    ↓
BEGIN/START TRANSACTION
    ↓
SQL операции (INSERT, UPDATE, DELETE)
    ↓
COMMIT (успешно) ← все изменения постоянны
ROLLBACK (ошибка) ← все изменения отменены

Autocommit режим

В большинстве JDBC драйверов по умолчанию включен autocommit = true:

Connection conn = DriverManager.getConnection(url, user, password);
// autoCommit = true по умолчанию

Statement stmt = conn.createStatement();
stmt.executeUpdate("UPDATE accounts SET balance = 900 WHERE id = 1");
// COMMIT происходит автоматически после executeUpdate

Это удобно для простых операций, но опасно для сложных транзакций:

conn.setAutoCommit(false);  // Отключаем для контроля
Statement stmt = conn.createStatement();
stmt.executeUpdate("UPDATE accounts SET balance = 900 WHERE id = 1");
stmt.executeUpdate("UPDATE accounts SET balance = 1100 WHERE id = 2");
// Без явного COMMIT изменения не фиксируются
conn.commit();  // Теперь фиксируем обе операции атомарно

С использованием ORM (Hibernate)

При работе с Hibernate/JPA COMMIT обычно происходит автоматически в конце транзакции:

@Service
@Transactional  // Начинает транзакцию
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
    Account from = accountRepository.findById(fromId).orElseThrow();
    Account to = accountRepository.findById(toId).orElseThrow();
    
    from.setBalance(from.getBalance().subtract(amount));
    to.setBalance(to.getBalance().add(amount));
    
    // В конце метода @Transactional автоматически выполняет COMMIT
    // Если выброшено исключение - ROLLBACK
}

Важные моменты

1. COMMIT делает изменения видимыми для других сессий:

// Сессия 1
conn1.setAutoCommit(false);
stmt1.executeUpdate("UPDATE accounts SET balance = 900 WHERE id = 1");
// Сессия 2 НЕ видит это изменение (isolation level)

conn1.commit();
// Теперь Сессия 2 видит новое значение

2. COMMIT должен быть в блоке try-catch:

try {
    conn.setAutoCommit(false);
    // операции
    conn.commit();
} catch (SQLException e) {
    try {
        conn.rollback();
    } catch (SQLException rollbackEx) {
        logger.error("Rollback failed", rollbackEx);
    }
}

3. COMMIT может быть медленным:

Если транзакция большая, COMMIT может занять время:

conn.setAutoCommit(false);
for (int i = 0; i < 100000; i++) {
    stmt.executeUpdate("INSERT INTO logs VALUES (" + i + ")");
}
long startTime = System.currentTimeMillis();
conn.commit();  // Это может занять несколько секунд
long duration = System.currentTimeMillis() - startTime;
logger.info("COMMIT took: " + duration + "ms");

4. Уровень изоляции влияет на COMMIT:

conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
conn.setAutoCommit(false);
// Более строгая изоляция → медленнее COMMIT

Лучшие практики

1. Минимизируй размер транзакции:

// Плохо - большая транзакция
conn.setAutoCommit(false);
for (int i = 0; i < 100000; i++) {
    stmt.executeUpdate("INSERT INTO data VALUES (" + i + ")");
}
conn.commit();  // Долгий COMMIT

// Хорошо - батчи
conn.setAutoCommit(false);
for (int i = 0; i < 100000; i++) {
    stmt.addBatch("INSERT INTO data VALUES (" + i + ")");
    if (i % 1000 == 0) {
        stmt.executeBatch();
        conn.commit();  // Часто, но быстро
    }
}

2. Всегда откатывай при ошибке:

try {
    conn.setAutoCommit(false);
    // операции
    conn.commit();
} catch (Exception e) {
    conn.rollback();  // ОБЯЗАТЕЛЬНО!
    throw new RuntimeException("Transaction failed", e);
}

3. Используй @Transactional аннотацию вместо ручного управления:

@Transactional  // Управление автоматическое
public void complexOperation() {
    // код
}  // COMMIT/ROLLBACK происходят сами

COMMIT — это не просто SQL команда, это гарантия целостности данных. Неправильное использование может привести к потере данных или несогласованности БД.

Что такое COMMIT в SQL? | PrepBro