❌ Ошибка 1: SQL-инъекция через f-строки
# Неправильно
username = input("Enter username: ")
cursor.execute(f"SELECT id FROM users WHERE username = '{username}'")
Сообщение об ошибке: ошибки может не быть, но злоумышленник может ввести ' OR '1'='1 и получить доступ к чужим данным.
Почему возникает: пользовательский ввод напрямую подставляется в текст SQL-запроса, нарушая его структуру.
✅ Исправление
# Правильно
cursor.execute("SELECT id FROM users WHERE username = %s", (username,))
Что изменилось: значение передаётся вторым аргументом, и PyMySQL сам экранирует спецсимволы.
❌ Ошибка 2: Забытый connection.commit()
# Неправильно
cursor.execute("INSERT INTO users (username, password) VALUES (%s, %s)", (user, pwd))
# commit забыт!
print("Registration successful.")
Сообщение об ошибке: ошибки нет, но после переподключения данные отсутствуют.
Почему возникает: PyMySQL по умолчанию работает в режиме транзакций. Изменения сохраняются только после явного вызова commit().
✅ Исправление
# Правильно
cursor.execute("INSERT INTO users (username, password) VALUES (%s, %s)", (user, pwd))
connection.commit()
print("Registration successful.")
Что изменилось: после выполнения запроса вызывается commit(), чтобы зафиксировать изменения в базе.
❌ Ошибка 3: Не закрытый курсор
# Неправильно
cursor = connection.cursor()
cursor.execute("SELECT * FROM books")
# cursor не закрыт явно
Сообщение об ошибке: при большом числе запросов может закончиться пул курсоров или произойти утечка ресурсов.
Почему возникает: курсор занимает ресурсы сервера и клиента; незакрытые курсоры могут приводить к утечкам.
✅ Исправление
# Правильно
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM books")
rows = cursor.fetchall()
Что изменилось: контекстный менеджер with автоматически закрывает курсор после использования.
❌ Ошибка 4: Путаница индексов в fetchone()
# Неправильно
result = cursor.fetchone()
book_id = result[0]
current_stock = result[2] # ошибка: stock на самом деле под индексом 4
Сообщение об ошибке: IndexError: tuple index out of range или логическая ошибка с неверными данными.
Почему возникает: индексы в кортеже зависят от порядка столбцов в SELECT. Если запрос изменится, индексы перестанут соответствовать ожидаемым полям.
✅ Исправление
# Правильно: явно укажите нужные столбцы и распакуйте кортеж
cursor.execute("SELECT id, stock FROM books WHERE title = %s AND author = %s", (title, author))
result = cursor.fetchone()
if result is None:
print("Book not found")
else:
book_id, current_stock = result
Что изменилось: запрос выбирает только нужные столбцы в нужном порядке, а результат распаковывается по именам переменных. Также добавлена проверка на None.
❌ Ошибка 5: Неправильная обработка отсутствующей книги
# Неправильно
result = cursor.fetchone()
if result: # иногда пишут if result is True, что неверно
book_id, stock = result
Сообщение об ошибке: TypeError: cannot unpack non-iterable NoneType object.
Почему возникает: fetchone() возвращает None, если строка не найдена. Попытка распаковать None приводит к ошибке.
✅ Исправление
# Правильно
result = cursor.fetchone()
if result is None:
# добавляем новую книгу
pass
else:
book_id, current_stock = result
# обновляем количество
Что изменилось: перед распаковкой явно проверяем, что result не None.
❌ Ошибка 6: Забытый USE перед работой с таблицами
# Неправильно
cursor.execute("CREATE DATABASE IF NOT EXISTS bookstore")
cursor.execute("CREATE TABLE IF NOT EXISTS books (...)") # таблица создаётся не в той базе!
Сообщение об ошибке: таблица создаётся в текущей базе данных по умолчанию, а не в bookstore.
Почему возникает: после создания базы нужно явно переключиться на неё командой USE.
✅ Исправление
# Правильно
cursor.execute("CREATE DATABASE IF NOT EXISTS bookstore")
cursor.execute("USE bookstore")
cursor.execute("CREATE TABLE IF NOT EXISTS books (...)")
Что изменилось: добавлена команда USE bookstore перед созданием таблиц.