JavaRush /Курси /Модуль 5. Spring /Вступ до управління транзакціями в Spring

Вступ до управління транзакціями в Spring

Модуль 5. Spring
Рівень 6 , Лекція 1
Відкрита

Spring Framework бере на себе всю мороку з транзакціями в додатку. Тобі достатньо позначити метод анотацією @Transactional, і Spring автоматично обгорне його виконання в транзакцію. Жодних явних begin, commit або rollback — фреймворк сам вирішує, коли почати транзакцію і як її завершити.

Види управління транзакціями

У Spring є два способи управління транзакціями:

  1. Декларативне управління транзакціями. Налаштовується анотаціями на кшталт @Transactional і використовується у 99% випадків (мінімум коду, максимум магії Spring).
  2. Програмне управління транзакціями. Коли потрібен тонший контроль, можна використовувати спеціальні класи, такі як TransactionTemplate.

Ми зосередимося на декларативному підході до управління транзакціями, хоча й торкнемося програмного. З декларативним підходом більшість задач вирішується однією анотацією — жодного ручного управління транзакціями, усе відбувається автоматично.

Архітектура управління транзакціями в Spring

За лаштунками транзакцій у Spring працює складний механізм. Як Spring знає, де почати транзакцію? Коли її завершити? І хто взагалі стежить за всім цим процесом? Давай розберемо, як усе влаштовано.

TransactionManager: головний диригент транзакцій

Spring використовує концепцію TransactionManager для управління транзакціями. Це центральний компонент, який координує початок, завершення і відкат транзакцій.

Ось основні реалізації, які найчастіше зустрічаються:

  • DataSourceTransactionManager — працює з JDBC (старий добрий SQL).
  • JpaTransactionManager — для тих, хто використовує JPA/Hibernate. Ми будемо працювати з ним у багатьох прикладах.
  • JtaTransactionManager — підходить для розподілених транзакцій через JTA (Java Transaction API).

Spring автоматично обирає підходящий TransactionManager, виходячи з твоїх залежностей. Тож, якщо ти використовуєш JPA, не дивуйся, коли побачиш, як Spring усе "вгадує". Друзі, це не вгадування — це Spring-автоконфігурація!


Підтримка різних технологій

Важливо зазначити, що Spring може керувати транзакціями на багатьох платформах і технологіях, включно з:

  • JDBC — для роботи напряму з базами даних.
  • JPA/Hibernate — для ORM-рішень.
  • JTA — для роботи в розподілених системах (наприклад, мікросервісах).

Хочеш більше прикладів? Тоді давай створимо менеджера транзакцій у реальному додатку.


Приклад налаштування TransactionManager

Для роботи з транзакціями нам потрібно додати в наш додаток менеджер транзакцій. Налаштування в Spring Boot неймовірно просте. Розглянемо приклад для роботи з JPA:


@Configuration
@EnableTransactionManagement // Вмикаємо управління транзакціями
public class AppConfig {

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf); // Менеджер для JPA
    }
}

Ось і все! Тепер Spring знає, який менеджер потрібно використовувати для управління транзакціями.


Трохи про декларативне і програмне управління

Давай швидко розберемо дві стратегії управління транзакціями, які пропонує Spring.

Декларативне управління транзакціями

У декларативному підході ти просто анотуєш метод або клас анотацією @Transactional. Spring бере на себе турботу про те, щоб почати транзакцію перед виконанням методу і завершити її після.

Приклад:


@Service
public class BankService {

    @Transactional
    public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {
        // Логіка переведення грошей
        accountRepository.debit(fromAccountId, amount);
        accountRepository.credit(toAccountId, amount);
    }
}

Як бачиш, жодних ручних викликів begin() або commit() — тільки анотація і чистий бізнес-код.

Програмне управління транзакціями

Інколи треба керувати транзакціями вручну. Наприклад, якщо потрібне складне розгалуження логіки, де кожна гілка може працювати в своїй транзакції.

Приклад:


@Service
public class ManualTransactionService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void performAction() {
        TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);

        transactionTemplate.execute(status -> {
            // Твій код всередині транзакції
            performSomeDBOperations();
            return null; // null означає, що все пройшло успішно
        });
    }
}

Непогано, правда? Але давай будемо чесними: програмний підхід — це скоріше виняток, ніж правило.


Як працює транзакційне управління в Spring

Spring використовує AOP (аспектно-орієнтоване програмування) для управління транзакціями. Коли ти анотуєш метод @Transactional, Spring фактично створює проксі-об'єкт для твого біну. Цей проксі перехоплює виклики методів і обгортає їх у транзакції.

Простими словами:

  1. Перед викликом методу: Spring відкриває транзакцію.
  2. Виклик методу: виконується твій бізнес-код.
  3. Після виклику: транзакція або фіксується, або відкочується (якщо сталася помилка).

Приклад: налаштування транзакції і її використання

Давай розберемося з повною налаштуванням транзакцій у Spring Boot. Уявимо простий додаток для управління книжками в бібліотеці. Нам потрібно створити сутність Book, репозиторій, сервіс-слой і контролер.

Сутність Book


@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private String author;

    // Гетери і сетери...
}

Репозиторій

Ми будемо використовувати JpaRepository для роботи з базою даних.


public interface BookRepository extends JpaRepository<Book, Long> {
    // Ніякого коду тут не потрібно, магія JpaRepository робить усе за нас
}

Сервіс-слой з транзакцією


@Service
public class BookService {

    private final BookRepository bookRepository;

    @Autowired
    public BookService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @Transactional
    public Book saveBook(Book book) {
        return bookRepository.save(book);
    }

    @Transactional
    public void deleteBook(Long id) {
        bookRepository.deleteById(id);
    }
}

Тут ми говоримо Spring: "Ей, друже, обгорни всі методи в транзакцію!"

Контролер


@RestController
@RequestMapping("/books")
public class BookController {

    private final BookService bookService;

    @Autowired
    public BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @PostMapping
    public ResponseEntity<Book> createBook(@RequestBody Book book) {
        Book createdBook = bookService.saveBook(book);
        return ResponseEntity.ok(createdBook);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
        bookService.deleteBook(id);
        return ResponseEntity.noContent().build();
    }
}

Тепер ти можеш створювати й видаляти книжки у своїй бібліотеці, і все це під транзакціями.


Важливі нюанси: про помилки та несподівані проблеми

Однією з частих помилок є анотування приватних методів анотацією @Transactional. Пам'ятай, транзакції працюють через проксі, а отже, Spring бачить лише виклики публічних методів.

Також важливо пам'ятати, що якщо метод викликає інший метод того ж класу, анотація @Transactional на другому методі може бути проігнорована.


Ти бачиш, наскільки просто й елегантно Spring справляється з транзакціями, надаючи нам потужний інструмент для управління даними та узгодженістю. У наступних лекціях ми заглибимося в анотацію @Transactional і її налаштування. Готуйся до нових відкриттів!

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ