Вопрос проверяет понимание стратегий управления конкурентным доступом к данным в многопользовательских системах, что необходимо для предотвращения конфликтов и обеспечения целостности данных.
В многопользовательских приложениях, где несколько клиентов могут одновременно пытаться изменить одни и те же данные, возникает проблема конкурентного доступа. Для её решения используются две основные стратегии: оптимистическая и пессимистическая блокировки. Они кардинально различаются в подходе к управлению параллелизмом.
Эта стратегия исходит из предположения, что конфликты при одновременном изменении данных случаются редко. Поэтому она не блокирует данные на время чтения. Вместо этого, при сохранении изменений, система проверяет, не изменились ли данные с момента их чтения. Обычно это реализуется с помощью поля версии (например, version или timestamp).
Пример работы:
id=1 и version=5.version=5.WHERE id=1 AND version=5. Сохранение проходит успешно, версия обновляется до 6.WHERE id=1 AND version=5. Эта операция завершится ошибкой, так как текущая версия в БД уже равна 6. Пользователю Б нужно будет перечитать актуальные данные и повторить операцию.Пример кода на Python с использованием SQLAlchemy:
# Модель с полем версии
class Product(Base):
__tablename__ = 'products'
id = Column(Integer, primary_key=True)
name = Column(String)
stock = Column(Integer)
version = Column(Integer, default=1)
# Оптимистическое обновление
def update_product_stock(session, product_id, new_stock):
product = session.query(Product).get(product_id)
old_version = product.version
product.stock = new_stock
product.version = old_version + 1
# Попытка сохранить с проверкой версии
rows_updated = session.query(Product).filter(
Product.id == product_id,
Product.version == old_version
).update({
'stock': new_stock,
'version': old_version + 1
})
if rows_updated == 0:
session.rollback()
raise Exception('Конфликт версий: данные были изменены другим пользователем.')Эта стратегия предполагает, что конфликты очень вероятны. Поэтому при чтении данных с целью их последующего изменения запись сразу блокируется для других транзакций (обычно с помощью конструкций вроде SELECT ... FOR UPDATE в SQL). Блокировка удерживается до конца текущей транзакции (commit или rollback).
Пример работы:
SELECT * FROM accounts WHERE id=1 FOR UPDATE. Запись с id=1 блокируется.SELECT ... FOR UPDATE для той же записи. Его запрос будет ждать, пока пользователь А не завершит свою транзакцию.Пример на SQL:
-- Транзакция пользователя А
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 1 FOR UPDATE; -- Блокировка установлена
-- ... выполняем вычисления нового баланса
UPDATE accounts SET balance = 1500 WHERE id = 1;
COMMIT; -- Блокировка снимается
-- Транзакция пользователя Б будет ждать на SELECT ... FOR UPDATE,
-- пока пользователь А не сделает COMMIT.Вывод: Оптимистическая блокировка — это стратегия "проверь и потом сохрани", идеальная для сценариев с высокой читаемостью и редкими конфликтами, например, в веб-приложениях с большим количеством чтений. Пессимистическая блокировка — стратегия "заблокируй, потом изменяй", которая необходима в системах с высокой конкуренцией за одни и те же данные, где важно гарантировать последовательность изменений, таких как банковские системы или системы управления запасами.