JavaRush /Курси /Модуль 5. Spring /Що таке транзакції і навіщо вони потрібні

Що таке транзакції і навіщо вони потрібні

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

Щодня ми стикаємося з операціями, які мають бути виконані цілком або не виконані взагалі. Уяви банківський переказ: гроші мають зникнути з одного рахунку і з’явитися на іншому. Завіснути десь посередині вони не можуть. У програмуванні такі операції називаються транзакціями.

Транзакція як базова одиниця роботи

Транзакція — це група операцій, які мають виконатися як єдине ціле. Або всі операції проходять успішно (commit), або система відкатує всі зміни назад (rollback), нібито нічого й не було. Це як система контрольних точок у грі: якщо щось пішло не так, ти завжди можеш повернутися до останнього збереження.

Щоб транзакція вважалася коректною, вона має володіти наступними властивостями, які об’єднуються в абревіатурі ACID:

Властивість Опис
Атомарність (Atomicity) Усі операції всередині транзакції виконуються як єдине ціле. Або всі, або нічого
Консистентність (Consistency) Після завершення транзакції система перебуває у коректному стані
Ізоляція (Isolation) Операції транзакції ізольовані від паралельних транзакцій (ніяких «втручань»)
Довговічність (Durability) Після завершення транзакції її результати зберігаються навіть у разі збою системи

Уявімо собі банківський переказ. Ти хочеш перевести гроші зі свого рахунку на рахунок друга. Процес можна розбити на такі кроки: 1. Зменшити суму на твоєму рахунку. 2. Збільшити суму на рахунку друга.

Якщо станеться збій між цими кроками (наприклад, перерветься з’єднання з банком), то ми ризикуємо або «втратити» гроші, або «створити» їх із повітря. Щоб уникнути таких ситуацій, обидві операції об’єднуються в транзакцію. Якщо один із кроків не вдається, то всі зміни відкочуються, і система повертається в початковий стан.


Навіщо потрібні транзакції в додатках

У світі розробки транзакції грають ключову роль для забезпечення коректності даних, особливо коли додатки працюють із базами даних. Давай розберемо, чому без них не обійтися.

Забезпечення узгодженості даних

Повернемося до прикладу з банківським переказом: уяви, що банківський сервер раптово «впав» після списання грошей з твого рахунку. Без транзакцій твій друг не отримає переказ, а ти залишишся без грошей. Не найприємніша ситуація, правда?

Транзакції вирішують цю проблему елегантно: або гроші успішно переїдуть, або повернуться на твій рахунок — ніяких завислих платежів. Це критично важливо для серйозних додатків: інтернет-магазинів, систем бронювання, медичних платформ.

Робота в багатокористувацькому середовищі

У сучасних додатках часто виникають ситуації, коли кілька користувачів намагаються змінити ті самі дані:

  • Два покупці прицілилися на останню пару кросівок
  • Кілька менеджерів одночасно редагують картку клієнта в CRM

Без транзакцій це може привести до справжнього хаосу в даних. Транзакції ж діють як розумний регулятор — не дають операціям заважати одна одній.


Проблеми, які вирішують транзакції

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

Запобігання частковим змінам

Уяви, що ти працюєш над моделлю замовлення в інтернет-магазині. Створення замовлення може включати такі кроки:

  1. Створити запис про нове замовлення в базі даних.
  2. Зменшити кількість доступного товару на складі.
  3. Відправити повідомлення користувачу.

Якщо станеться збій, наприклад, на другому кроці, то з’явиться ситуація «часткової завершеності»: замовлення буде числитися в системі, але товар все ще буде числитися як доступний. Це може привести до серйозних проблем, особливо в масштабованих системах. Транзакції допомагають уникнути таких сценаріїв.

Цілісність даних при збоях

Збоїв, як ми знаємо, не уникнути. Наприклад:

  • Щось пішло не так при збереженні даних у базу.
  • Впала мережа.
  • Додаток викинув виключення.

З хорошою транзакційною системою ти можеш бути впевнений: жодні «биті» зміни не потраплять у твою базу даних.

Усунення конфліктів при паралельній роботі

Ще одна проблема — коли кілька процесів або користувачів одночасно намагаються змінити ті самі дані. Наприклад:

  1. Працівник А додав коментар у CRM.
  2. Працівник Б одночасно видалив цей самий коментар.

Хто переможе? Без механізму ізоляції транзакцій результат може бути непередбачуваним. Однак при правильному налаштуванні паралельні транзакції будуть захищені від втручання одна в одну.


Приклад: транзакції в інтернет-магазині

Давай створимо простий приклад, де транзакції використовуються для обробки замовлення в інтернет-магазині. Наш сценарій:

  1. Створити запис про нове замовлення.
  2. Зменшити запас товару на складі.
  3. Якщо станеться збій на будь-якому з кроків, відкотити всі зміни.

@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private InventoryService inventoryService;

    @Transactional
    public void processOrder(OrderRequest orderRequest) {
        // Крок 1: Створення нового замовлення
        Order order = new Order();
        order.setProductId(orderRequest.getProductId());
        order.setQuantity(orderRequest.getQuantity());
        order.setStatus("PROCESSING");
        orderRepository.save(order);

        // Крок 2: Зменшення запасу на складі
        inventoryService.reduceStock(orderRequest.getProductId(), orderRequest.getQuantity());

        // Крок 3: Оновити статус замовлення на "COMPLETED"
        order.setStatus("COMPLETED");
        orderRepository.save(order);
    }
}

Що тут відбувається?

  • Ми позначаємо метод processOrder() як транзакційний за допомогою анотації @Transactional. Це означає, що всі операції всередині методу виконуються в одній транзакції.
  • Якщо на будь-якому етапі трапиться помилка (наприклад, товар закінчився), зміни будуть автоматично відкоті, і база даних залишиться в узгодженому стані.

Приклад помилки і відкату

Давай додамо «штучну» помилку, щоб перевірити, що транзакція справді відкочується.


public void reduceStock(String productId, int quantity) {
    int currentStock = inventoryRepository.getStock(productId);
    if (currentStock < quantity) {
        throw new RuntimeException("Insufficient stock for product: " + productId);
    }
    inventoryRepository.updateStock(productId, currentStock - quantity);
}

Якщо товару недостатньо, метод reduceStock викине виключення, і вся транзакція буде скасована: замовлення не буде збережене, і запаси на складі не зміняться.


Реальне застосування

У реальних проєктах транзакції використовуються практично всюди:

  • Банківські операції (перекази, поповнення, зняття з рахунку).
  • Замовлення і бронювання (купівля квитків, готелі).
  • Управління даними в корпоративних системах (CRM, ERP).

Чому це важливо для нас? Якщо на співбесіді тебе запитають, як обробити банківську операцію або захистити дані від конфліктів, ти, як досвідчений Java-розробник зі Spring, зможеш не тільки розповісти про транзакції, а й наочно показати код з @Transactional.

Тепер ми готові перейти до наступного кроку: управління транзакціями в Spring за допомогою анотації @Transactional та інших інструментів.

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