Оптимістичне блокування (шаблон проєктування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Оптимістичне блокування (англ. Optimistic Offline Lock) — шаблон проєктування, який запобігає конфлікту між бізнес-транзакціями, що конкурують шляхом їх виявлення та відкату транзакції.

Опис[ред. | ред. код]

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

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

Даний шаблон варто використовувати тоді коли шанси на конфлікт не великі (доступ до одних і тих самих даних різними користувачами відбувається рідко), або ж тоді коли не має суворої вимоги в дотримані консистенції даних.

Алгоритм[ред. | ред. код]

  • Клієнт 1 отримує запис під номером 19 із номером версії 1.
  • Клієнт 2 отримує той самий запис під номером 19 із номером версії 1.
  • Обидва клієнти роблять зміни над одними і тими самими даними.
  • Клієнт 2 зберігає свої зміни в сховищі та збільшує номер версії до 2.
  • Клієнт 1 намагається зберегти свої зміни. Він перевіряє номер версії свого запису із тим що в сховищі та бачить що вони відрізняються. Клієнт може скасувати транзакцію, або ж перевірити наявність конфлікту між даними та спробувати його вирішити.

Реалізація[ред. | ред. код]

При реалізації нам необхідно до сутності додати номер версії

public class User
{
    public int Id { get; set; }
    public int RevisionNumber { get; set; }
    // як альтернатива номеру версії може бути значення дня останньої зміни
    // public DateTime UpdatedAt { get; set; }
}

Тоді при збережені змін нам варто перевірити чи номер версії нашого запису збігається із тим, що в сховищі.

public void Update(UserDto userDto)
{
    User user = db.GetUser(userDto.UserId);

    if (user.RevisionNumber != userDto.RevisionNumber)
    {
        db.Rollback();

        return;
    }

    db.Update(userDto);
}

Див. також[ред. | ред. код]

Джерела[ред. | ред. код]