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

Как управлять возвратом транзакции

2.0 Middle🔥 191 комментариев
#Spring Framework#Базы данных и SQL

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

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

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

Управление откатом транзакции в Java

Транзакция — это последовательность операций над БД, которая либо полностью выполнится (commit), либо полностью откатится (rollback). Правильное управление транзакциями критично для целостности данных.

1. JDBC – ручное управление

Connection conn = getConnection();

try {
    conn.setAutoCommit(false); // отключи автокоммит
    
    // операция 1
    PreparedStatement stmt1 = conn.prepareStatement("INSERT INTO accounts SET balance = ?");
    stmt1.setDouble(1, 500.00);
    stmt1.executeUpdate();
    
    // операция 2
    PreparedStatement stmt2 = conn.prepareStatement("UPDATE accounts SET balance = balance - ?");
    stmt2.setDouble(1, 500.00);
    stmt2.executeUpdate();
    
    conn.commit(); // всё прошло успешно
    
} catch (SQLException e) {
    try {
        conn.rollback(); // откати всё при ошибке
    } catch (SQLException ex) {
        ex.printStackTrace();
    }
    throw new RuntimeException(e);
} finally {
    try {
        conn.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

2. Try-with-resources (Java 7+)

Автоматически закрывает ресурсы:

try (Connection conn = getConnection()) {
    conn.setAutoCommit(false);
    
    try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO users VALUES (?, ?)")) {
        stmt.setInt(1, 1);
        stmt.setString(2, "John");
        stmt.executeUpdate();
    }
    
    conn.commit();
} catch (SQLException e) {
    // rollback() вызовется автоматически если выбросится исключение
    throw new RuntimeException(e);
}

3. Spring @Transactional (декларативные транзакции)

Самый удобный способ — аннотация @Transactional:

@Service
public class PaymentService {
    
    @Autowired
    private AccountRepository accountRepo;
    
    @Transactional
    public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
        Account from = accountRepo.findById(fromId).orElseThrow();
        Account to = accountRepo.findById(toId).orElseThrow();
        
        from.setBalance(from.getBalance().subtract(amount));
        to.setBalance(to.getBalance().add(amount));
        
        accountRepo.save(from);
        accountRepo.save(to);
        
        // если выброситься исключение — rollback автоматически
    }
}

Параметры @Transactional:

@Transactional(
    propagation = Propagation.REQUIRED,  // создать новую или использовать существующую
    isolation = Isolation.READ_COMMITTED, // уровень изоляции
    readOnly = false,                     // можно ли читать
    timeout = 30,                         // timeout в секундах
    rollbackFor = Exception.class         // откатывать на все исключения
)
public void criticalOperation() { ... }

4. Явный откат в Spring

@Transactional
public void processPayment(Payment payment) {
    if (isRisky(payment)) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        throw new BusinessException("Risky payment detected");
    }
    // сохранение
}

5. Savepoint (точки сохранения)

Для частичного отката:

try (Connection conn = getConnection()) {
    conn.setAutoCommit(false);
    
    // операция 1
    executeUpdate(conn, "INSERT INTO logs VALUES (1, Start)");
    
    // точка сохранения
    Savepoint sp = conn.setSavepoint("checkpoint1");
    
    try {
        // операция 2 (может упасть)
        executeUpdate(conn, "INSERT INTO risky_operation ...");
    } catch (Exception e) {
        conn.rollback(sp); // откати только до savepoint
    }
    
    conn.commit();
}

6. Уровни изоляции транзакций

// READ_UNCOMMITTED — очень низкий
// READ_COMMITTED — дефолт, защита от dirty reads
// REPEATABLE_READ — защита от non-repeatable reads
// SERIALIZABLE — максимальная изоляция (медленно)

@Transactional(isolation = Isolation.REPEATABLE_READ)
public void criticalRead() { ... }

Итого

  • JDBC: вручную управляй setAutoCommit(false), commit(), rollback()
  • Spring: используй @Transactional для простоты
  • Savepoint: для частичных откатов
  • Уровни изоляции: выбирай в зависимости от требований
  • Всегда закрывай ресурсы: try-with-resources или finally блоки
Как управлять возвратом транзакции | PrepBro