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

Как реализовать Optimistic Locking

1️⃣ Как кратко ответить

Optimistic Locking реализуется с использованием версии данных. При обновлении записи проверяется, что версия данных не изменилась с момента последнего чтения. Если версия изменилась, операция отклоняется, предотвращая перезапись изменений, сделанных другими транзакциями.

2️⃣ Подробное объяснение темы

Optimistic Locking — это стратегия управления конкурентным доступом к данным, которая предполагает, что конфликтов при доступе к данным будет немного. Она позволяет нескольким транзакциям читать данные одновременно, но при обновлении данных проверяет, что они не изменились с момента последнего чтения.

Зачем это нужно

Optimistic Locking используется для предотвращения потери данных в многопользовательских системах, где несколько транзакций могут пытаться обновить одну и ту же запись одновременно. Это особенно полезно в системах с высокой степенью параллелизма, где блокировки могут стать узким местом.

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

Основная идея заключается в использовании специального поля, называемого "версионным полем" (например, version), в каждой записи базы данных. Это поле обновляется при каждом изменении записи. Когда транзакция читает данные, она также читает текущее значение версии. При попытке обновления данных транзакция проверяет, что версия не изменилась. Если версия изменилась, это означает, что другая транзакция уже обновила данные, и текущая транзакция должна быть отклонена или повторена.

Пример реализации

Рассмотрим пример на Java с использованием JPA (Java Persistence API):

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Version;
​
@Entity
public class Product {
​
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
​
    private String name;
​
    private double price;
​
    // Поле версии для Optimistic Locking
    @Version
    private int version;
​
    // Геттеры и сеттеры
    public Long getId() {
        return id;
    }
​
    public void setId(Long id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public double getPrice() {
        return price;
    }
​
    public void setPrice(double price) {
        this.price = price;
    }
​
    public int getVersion() {
        return version;
    }
​
    public void setVersion(int version) {
        this.version = version;
    }
}

Объяснение кода

  • @Entity: Аннотация указывает, что класс Product является сущностью JPA и будет отображаться в таблицу базы данных.
  • @Id: Аннотация указывает, что поле id является первичным ключом.
  • @GeneratedValue: Указывает стратегию генерации значений для первичного ключа. В данном случае используется автоинкремент.
  • @Version: Аннотация указывает, что поле version используется для Optimistic Locking. JPA автоматически будет увеличивать это поле при каждом обновлении записи.

Пример использования

Предположим, у нас есть два пользователя, которые одновременно читают и пытаются обновить одну и ту же запись:

  1. Пользователь A читает запись Product с version = 1.
  2. Пользователь B читает ту же запись с version = 1.
  3. Пользователь A обновляет запись, увеличивая version до 2.
  4. Пользователь B пытается обновить запись, но обнаруживает, что version изменилась с 1 на 2. Обновление отклоняется.

Применение

Optimistic Locking подходит для систем, где чтение данных происходит чаще, чем их обновление, и где блокировки могут негативно сказаться на производительности. Это позволяет избежать блокировок на уровне базы данных, что может быть критично для высоконагруженных систем.

Тема: Многопоточность
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки