← Назад к вопросам
Что делает транзакционный метод?
1.8 Middle🔥 201 комментариев
#Spring Framework#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Транзакционные методы в Java
Транзакционный метод — это метод, который выполняет группу операций с данными как единую неделимую (атомарную) операцию. Если что-то пойдёт не так, все изменения откатываются (rollback), как будто метод вообще не вызывался.
Основные характеристики
Транзакционный метод обеспечивает ACID-свойства:
- A (Atomicity) — либо всё выполнено, либо ничего
- C (Consistency) — данные в согласованном состоянии
- I (Isolation) — транзакции не мешают друг другу
- D (Durability) — результаты сохранены навсегда
Аннотация @Transactional (Spring)
В Java транзакции чаще всего управляются через Spring Framework:
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private PaymentService paymentService;
@Transactional
public Order createOrder(OrderRequest request) {
// Создаём заказ
Order order = new Order(request);
orderRepository.save(order);
// Обрабатываем платёж
paymentService.process(order);
// Если paymentService выбросит исключение,
// заказ не будет сохранён!
return order;
}
}
Как это работает
- Начало транзакции — открывается соединение с БД
- Выполнение операций — все команды SQL группируются
- Успех — COMMIT (фиксируем все изменения)
- Ошибка — ROLLBACK (откатываем всё)
@Transactional
public void transferMoney(String fromAccount, String toAccount, BigDecimal amount) {
// Шаг 1: Снять со счета
Account from = accountRepository.findById(fromAccount);
from.balance -= amount;
accountRepository.save(from);
// Шаг 2: Положить на счет
Account to = accountRepository.findById(toAccount);
to.balance += amount;
accountRepository.save(to);
// Если ошибка на любом шаге — оба счета вернутся в исходное состояние!
}
Типы транзакций
Isolation Levels (уровни изоляции)
// READ_UNCOMMITTED — можем читать незафиксированные данные
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void readUncommitted() { }
// READ_COMMITTED — по умолчанию, безопасно
@Transactional(isolation = Isolation.READ_COMMITTED)
public void readCommitted() { }
// REPEATABLE_READ — повторяемое чтение
@Transactional(isolation = Isolation.REPEATABLE_READ)
public void repeatableRead() { }
// SERIALIZABLE — самый строгий уровень
@Transactional(isolation = Isolation.SERIALIZABLE)
public void serializable() { }
Propagation (распространение)
@Transactional(propagation = Propagation.REQUIRED)
public void method1() {
// Использует существующую или создаёт новую
method2();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2() {
// Всегда создаёт НОВУЮ независимую транзакцию
}
@Transactional(propagation = Propagation.NESTED)
public void method3() {
// Вложенная транзакция (SAVEPOINT)
}
Практический пример
@Service
public class UserRegistrationService {
@Autowired
private UserRepository userRepository;
@Autowired
private EmailService emailService;
@Transactional
public User registerUser(UserRequest request) throws Exception {
// Создаём пользователя
User user = new User();
user.setEmail(request.getEmail());
user.setName(request.getName());
userRepository.save(user);
// Отправляем email
emailService.sendWelcomeEmail(user.getEmail());
// Если email не отправится — rollback, пользователь не создастся!
return user;
}
}
Readonly транзакции
@Transactional(readOnly = true)
public User getUser(String id) {
// Только чтение, оптимизировано для быстроты
return userRepository.findById(id);
}
// БД может оптимизировать этот запрос,
// так как никаких записей не будет
Обработка ошибок
@Transactional(rollbackFor = Exception.class)
public void processPayment(Payment payment) {
// Откатываем при ЛЮБОМ исключении
paymentRepository.save(payment);
// ...
}
@Transactional(noRollbackFor = ValidationException.class)
public void validate(Data data) {
// ValidationException НЕ вызывает откат
if (!isValid(data)) {
throw new ValidationException();
}
}
Проблемы с транзакциями
Deadlock (взаимная блокировка)
// Транзакция 1: блокирует Table1, хочет Table2
// Транзакция 2: блокирует Table2, хочет Table1
// → DEADLOCK!
Lost Update
// Транзакция 1: читает count = 5
// Транзакция 2: читает count = 5
// Транзакция 1: пишет count = 6
// Транзакция 2: пишет count = 6
// → Одно изменение потеряно!
Phantom Read
// Читаем строки WHERE age > 18 (10 строк)
// Другая транзакция добавляет ещё одну
// Читаем снова (уже 11 строк)
Проверка на production
@Transactional
@Logged // логируем начало и конец
@Timed // измеряем время
public void criticalOperation() {
// Spring покажет:
// - Начало транзакции
// - Все SQL запросы
// - COMMIT или ROLLBACK
// - Время выполнения
}
Добавь в application.yml:
spring:
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
dialect: org.hibernate.dialect.PostgreSQL10Dialect
Ключевые выводы
- Транзакция — гарантирует целостность данных
- @Transactional — включает управление транзакциями в Spring
- ACID — четыре свойства надёжной БД
- Откат — при ошибке все изменения отменяются
- Правильный уровень изоляции — критичен для конкурентного доступа
Транзакции — фундамент надёжных приложений, работающих с БД!