Забыть запятую в кортеже из одного значения: (value,).
Использовать f-string для SQL — это SQL-инъекция.
Не закрывать соединение и курсор.
Повторно вызывать fetchall() после исчерпания курсора.
Ловить голый Exception вместо конкретных ошибок MySQL.
Забывать commit() при INSERT/UPDATE/DELETE.
🐛 Типичные ошибки начинающих
1
Забыта запятая в кортеже из одного значения
Неправильно:
cursor.execute("SELECT * FROM employees WHERE id = %s", (100)) # целое число, не кортеж!
Правильно:
cursor.execute("SELECT * FROM employees WHERE id = %s", (100,)) # кортеж из одного элемента
Почему:(100) — это просто число 100 в скобках, а (100,) — кортеж. execute() ожидает последовательность параметров.
2
SQL-инъекция через f-string
Неправильно:
user_input = input("Введите ID: ")
cursor.execute(f"SELECT * FROM employees WHERE id = {user_input}")
Правильно:
user_input = input("Введите ID: ")
cursor.execute("SELECT * FROM employees WHERE id = %s", (user_input,))
Почему: пользователь может ввести 1 OR 1=1 и получить все строки таблицы.
3
Не закрыто соединение
Неправильно:
connection = pymysql.connect(**config)
cursor = connection.cursor()
cursor.execute("SELECT * FROM departments")
# соединение так и осталось открытым
Правильно:
with pymysql.connect(**config) as connection:
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM departments")
for row in cursor:
print(row)
Почему: открытые соединения расходуют ресурсы сервера и могут привести к исчерпанию лимита подключений.
4
Вызов fetch после исчерпания курсора
Неправильно:
cursor.execute("SELECT * FROM departments")
all_rows = cursor.fetchall()
print(cursor.fetchone()) # None, ожидалась первая строка
Правильно:
cursor.execute("SELECT * FROM departments")
all_rows = cursor.fetchall()
print(all_rows[0]) # берём первую строку из уже полученных данных
Почему: курсор — однонаправленный итератор. После fetchall() читать больше нечего.
5
Ловля голого Exception
Неправильно:
try:
connection = pymysql.connect(**config)
except Exception as e:
print("Ошибка:", e)