← Назад к вопросам
Как управлять возвратом транзакции
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 блоки