Урок 82. MySQL. Транзакции

📁 Блок: Базы данных ⏱️ Время изучения: ~90 мин 🎯 Сложность: Средняя
#from #import #if #not #print #try #except #as

⚡ Кратко: старый vs новый подход

  • Кортежи от курсора → DictCursor для читаемости.
  • Ручной commit() вместо надежды на автокоммит.
  • Транзакция с rollback() вместо частичных изменений при ошибке.

⚖️ Старый vs Новый подход

1. Доступ к строкам: кортеж vs DictCursor

По умолчанию строки возвращаются как кортежи. Это компактно, но легко ошибиться с порядком индексов, особенно если колонок много.

Старый подходНовый подход
row = cursor.fetchone()
print(row[0])      # id
print(row[1])      # name
print(row[2])      # price
from pymysql.cursors import DictCursor
# cursorclass=DictCursor
row = cursor.fetchone()
print(row["id"])
print(row["name"])
print(row["price"])

Вывод: DictCursor делает код понятнее и снижает риск ошибок при изменении порядка колонок в запросе.

2. Сохранение изменений: надежда на автокоммит vs явный commit()

В PyMySQL по умолчанию автокоммит отключён. Если не вызвать commit(), изменения будут потеряны при закрытии соединения.

Старый подходНовый подход
cursor.execute("INSERT INTO products (name, price) VALUES (%s, %s)", ("Pen", 1.00))
# нет commit() — данные могут не сохраниться
cursor.execute("INSERT INTO products (name, price) VALUES (%s, %s)", ("Pen", 1.00))
connection.commit()  # явно фиксируем изменения

Вывод: всегда вызывай commit() после INSERT, UPDATE, DELETE.

⚠️ Проверить по документации: в PyMySQL по умолчанию autocommit=False. Если включить autocommit=True, каждый запрос будет фиксироваться сразу, но тогда теряется контроль над транзакциями.

3. Обработка ошибок: без отката vs rollback()

Если в последовательности изменений произойдёт ошибка, без rollback() часть изменений останется в базе, а часть — нет. Это нарушает целостность данных.

Старый подходНовый подход
cursor.execute("UPDATE products SET stock = stock - 1 WHERE id = %s", (product_id,))
cursor.execute("UPDATE customers SET balance = balance - %s WHERE id = %s", (price, customer_id))
# если второй запрос упадёт, товар уже списан
connection.commit()
try:
    cursor.execute("UPDATE products SET stock = stock - 1 WHERE id = %s", (product_id,))
    cursor.execute("UPDATE customers SET balance = balance - %s WHERE id = %s", (price, customer_id))
    connection.commit()
except Exception as e:
    connection.rollback()
    print("Transaction failed:", e)

Вывод: группируй связанные изменения в транзакцию и откатывай её при ошибке.