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

Что делает транзакционный метод?

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;
    }
}

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

  1. Начало транзакции — открывается соединение с БД
  2. Выполнение операций — все команды SQL группируются
  3. Успех — COMMIT (фиксируем все изменения)
  4. Ошибка — 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 — четыре свойства надёжной БД
  • Откат — при ошибке все изменения отменяются
  • Правильный уровень изоляции — критичен для конкурентного доступа

Транзакции — фундамент надёжных приложений, работающих с БД!