🐛 Типичные ошибки при работе с MySQL
Ошибка 1. Подстановка значений в SQL через f-string
user_input = input("Enter employee id: ")
cursor.execute(f"SELECT * FROM employees WHERE employee_id = {user_input}")
Такой код уязвим к SQL-инъекциям. Значения всегда нужно передавать вторым аргументом в execute().
cursor.execute(
"SELECT * FROM employees WHERE employee_id = %s",
(user_input,)
)
Ошибка 2. Забыть запятую в кортеже из одного элемента
cursor.execute(
"SELECT * FROM employees WHERE department_id = %s",
(100) # не кортеж, а число 100
)
Без запятой (100) — это просто число, а не кортеж. PyMySQL ожидает последовательность значений. Правильно:
cursor.execute(
"SELECT * FROM employees WHERE department_id = %s",
(100,) # кортеж из одного элемента
)
Ошибка 3. Забыть вызвать commit()
cursor.execute(
"INSERT INTO sales (item_name, quantity) VALUES (%s, %s)",
("Keyboard", 2)
)
# connection.commit() забыт
Без commit() INSERT, UPDATE и DELETE не сохраняются в базе. Изменения останутся только во временной транзакции и пропадут при закрытии соединения.
Ошибка 4. Не закрывать соединение и курсор
connection = pymysql.connect(**config)
cursor = connection.cursor()
cursor.execute("SELECT * FROM employees")
for row in cursor:
print(row)
# cursor.close() и connection.close() забыты
Незакрытые соединения занимают ресурсы сервера и могут исчерпать лимит подключений. Используйте with или finally.
Ошибка 5. Повторное чтение уже прочитанных данных
cursor.execute("SELECT * FROM employees")
rows1 = cursor.fetchall()
rows2 = cursor.fetchall() # пустой список
Курсор — это итератор. После того как все строки прочитаны, повторный вызов fetchall() вернёт пустой список. Чтобы прочитать данные заново, нужно выполнить запрос снова.
Ошибка 6. Обращение к несуществующей колонке в DictCursor
config["cursorclass"] = DictCursor
connection = pymysql.connect(**config)
cursor = connection.cursor()
cursor.execute("SELECT first_name FROM employees")
row = cursor.fetchone()
print(row["name"]) # KeyError
С DictCursor ключи словаря соответствуют именам колонок в запросе. Если в SELECT нет колонки name, возникнет KeyError.
Ошибка 7. Попытка выполнить запрос к таблице без выбора базы данных
config = {"host": "...", "user": "...", "password": "..."}
connection = pymysql.connect(**config)
cursor = connection.cursor()
cursor.execute("SELECT * FROM employees") # No database selected
Если при подключении не указан параметр database и не выполнена команда USE, запросы к таблицам вызовут ошибку No database selected.
Ошибка 8. Передача оператора сравнения как параметра
condition = ">"
salary = 10000
cursor.execute(
"SELECT * FROM employees WHERE salary %s %s",
(condition, salary)
)
PyMySQL экранирует все параметры как значения. Оператор сравнения нельзя передать через %s — он станет строкой и запрос не будет работать. Оператор нужно вставлять в строку запроса после проверки на допустимость.
Ошибка 9. Не откатывать транзакцию при ошибке
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))
cursor.execute("INSERT INTO purchases ...", (...))
connection.commit()
except Exception as e:
print("Error:", e)
# connection.rollback() забыт
Если в транзакции произошла ошибка, нужно вызвать rollback(), чтобы отменить частично выполненные изменения и сохранить целостность данных.
Ошибка 10. Использовать executemany() для SELECT
cursor.executemany(
"SELECT * FROM employees WHERE department_id = %s",
[(10,), (20,), (30,)]
)
Метод executemany() предназначен для изменяющих запросов: INSERT, UPDATE, DELETE. Для SELECT используйте execute() в цикле или параметризованный запрос с подходящим условием.
Ошибка 11. Не обрабатывать исключения при подключении
connection = pymysql.connect(
host="ich-db.edu.itcareerhub.de",
user="root",
password="wrong_password",
database="test"
)
# Если пароль неверный, программа аварийно завершится
Ошибки подключения и запросов нужно оборачивать в try/except, чтобы программа могла корректно сообщить о проблеме.
Ошибка 12. Создавать базу данных без прав на запись
config = {"host": "ich-db.edu.itcareerhub.de", "user": "ich1", "password": "password"}
connection = pymysql.connect(**config)
cursor.execute("CREATE DATABASE new_db") # может не хватить прав
Для создания баз и таблиц нужна учётная запись с правами на изменения. На серверах только для чтения такие операции вызовут ошибку доступа.