Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Свойства ACID в базах данных
ACID — это набор из четырёх ключевых свойств, обеспечивающих надёжность транзакций в базах данных. ACID гарантирует, что даже при сбоях система останется в согласованном состоянии.
A — Atomicity (Атомарность)
Определение: Транзакция либо выполнится полностью, либо не выполнится вообще (all-or-nothing).
# Пример: перевод денег между счётами
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Account(Base):
__tablename__ = 'accounts'
id = Column(Integer, primary_key=True)
name = Column(String)
balance = Column(Integer)
engine = create_engine('postgresql://...')
Session = sessionmaker(bind=engine)
def transfer_money(from_id, to_id, amount):
session = Session()
try:
# Начало транзакции
from_account = session.query(Account).filter_by(id=from_id).first()
to_account = session.query(Account).filter_by(id=to_id).first()
# Обе операции выполнятся вместе
from_account.balance -= amount
to_account.balance += amount
session.commit() # Успех: обе операции записаны
except Exception as e:
session.rollback() # Ошибка: откатываем ВСЕ операции
print(f"Transfer failed: {e}")
finally:
session.close()
# Если произойдёт ошибка (сбой питания), деньги не потеряются
Без атомарности: "снимаем 100₽ со счёта A" успешна, но "добавляем 100₽ на счёт B" падает → деньги исчезли.
C — Consistency (Согласованность)
Определение: БД переходит из одного согласованного состояния в другое. Все правила и ограничения сохраняются.
# Правило: баланс не может быть отрицательным
class Account(Base):
__tablename__ = 'accounts'
id = Column(Integer, primary_key=True)
balance = Column(Integer, CheckConstraint('balance >= 0')) # Правило БД
# Попытка снять больше, чем есть
try:
account = session.query(Account).get(1)
account.balance -= 1000 # На счёте только 500
session.commit() # БД отклонит это! CheckConstraint нарушен
except Exception:
session.rollback() # Состояние осталось согласованным
Консистентность гарантирует, что невозможны "неправильные" состояния БД.
I — Isolation (Изолированность)
Определение: Одновременные транзакции не влияют друг на друга. Результат выполнения n транзакций одновременно = результату их последовательного выполнения.
# Проблема без изоляции (грязное чтение)
# Транзакция 1: читает баланс = 100
# Транзакция 2: меняет баланс на 200
# Транзакция 1: читает баланс = 200 (противоречие!)
# Решение: уровни изолированности
# 1. READ UNCOMMITTED — видим незафиксированные изменения (грязное чтение)
# 2. READ COMMITTED — видим только зафиксированные данные
# 3. REPEATABLE READ — повторное чтение даст одинаковый результат
# 4. SERIALIZABLE — транзакции выполняются как последовательно
session = Session()
session.connection().execution_options(isolation_level="REPEATABLE READ")
# Теперь эта транзакция защищена
account = session.query(Account).filter_by(id=1).first()
balance_first = account.balance # 100
# Другая транзакция изменяет баланс
balance_second = account.balance # Всё ещё 100, не 200!
D — Durability (Долговечность)
Определение: Если транзакция зафиксирована (committed), данные сохраняются постоянно, даже при сбое системы.
# После commit() даже при отключении питания данные сохранятся
session.commit() # Точка невозврата
# Система сбилась — но данные уже на диске
# Механизм: Write-Ahead Logging (WAL)
# 1. Записываем в лог (диск) ДО фиксации
# 2. Фиксируем транзакцию
# 3. При восстановлении восстанавливаем из логов
Примеры нарушений
# ✗ Нарушение A (Atomicity)
delete_user(user_id=5) # Сбой
# Пользователь удалён, но его комментарии остались (orphaned records)
# ✗ Нарушение C (Consistency)
account.balance = -1000 # Отрицательный баланс! Неправильное состояние
# ✗ Нарушение I (Isolation)
# Транзакция 1 видит незафиксированные изменения транзакции 2
# ✗ Нарушение D (Durability)
insert_record()
commit()
# Сбой ОС → запись потеряна (если нет WAL)
ACID в Python приложении
from sqlalchemy import create_engine, event
from sqlalchemy.orm import sessionmaker
# Настройка для максимальной надёжности
engine = create_engine(
'postgresql://...',
isolation_level="SERIALIZABLE", # Самый строгий уровень
pool_pre_ping=True, # Проверяем соединение перед использованием
)
Session = sessionmaker(bind=engine)
def safe_transaction(func):
"""Декоратор для безопасных транзакций"""
def wrapper(*args, **kwargs):
session = Session()
try:
result = func(session, *args, **kwargs)
session.commit() # Commit = фиксируем
return result
except Exception as e:
session.rollback() # Откатываем при любой ошибке
raise e
finally:
session.close()
return wrapper
@safe_transaction
def transfer_between_accounts(session, from_id, to_id, amount):
from_account = session.query(Account).get(from_id)
to_account = session.query(Account).get(to_id)
from_account.balance -= amount
to_account.balance += amount
# session.commit() вызовется автоматически
Компромисс: BASE вместо ACID
Для высокой доступности некоторые системы используют BASE (Basically Available, Soft state, Eventually consistent):
# ACID: консистентно, но медленно
# BASE: быстро, но с временной несогласованностью
# NoSQL часто использует BASE (MongoDB, Cassandra)
Заключение
ACID — это гарантии, которые обеспечивают надёжность и корректность. Все реляционные БД (PostgreSQL, MySQL, SQLite) полностью поддерживают ACID. Это критично для систем, где важна целостность данных (банки, заказы, платежи).