Урок 80. MySQL и Python
⚡ Кратко: что меняется
- Старый подход: ручное создание соединения и курсора, ручной вызов
close()в блокеfinally. - Новый подход: контекстный менеджер
withзакрывает ресурсы автоматически, даже при ошибке. - SQL-инъекция: подстановка значений через f-string или конкатенацию опасна. Используй
%s/%(name)s.
⚖️ Ручное управление ресурсами vs контекстный менеджер
Раньше код часто писали так: создаём соединение, курсор, выполняем запросы и вручную закрываем ресурсы. Это работает, но легко забыть close() или пропустить ошибку.
Старый подход
import pymysql
connection = pymysql.connect(
host="localhost",
user="root",
password="yourpassword",
database="hr"
)
cursor = connection.cursor()
try:
cursor.execute("SELECT * FROM departments")
for row in cursor:
print(row)
finally:
cursor.close()
connection.close()
Недостатки:
- Нужно не забыть закрыть и курсор, и соединение.
- При нескольких точках выхода код разрастается.
- Если внутри
tryпроизойдёт ошибка доfinally, ресурсы всё равно закроются, но сам код громоздкий.
Новый подход
import pymysql
config = {
"host": "localhost",
"user": "root",
"password": "yourpassword",
"database": "hr"
}
with pymysql.connect(**config) as connection:
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM departments")
for row in cursor:
print(row)
Преимущества:
- Меньше кода и он чище.
- Ресурсы закрываются автоматически при выходе из блока.
- Даже при исключении
close()будет вызван.
🛡️ SQL-инъекция: f-string vs параметризованный запрос
Подстановка пользовательского ввода в SQL через f-string или сложение строк делает программу уязвимой.
Опасный код
user_input = "1 OR 1=1"
sql = f"SELECT * FROM employees WHERE employee_id = {user_input}"
cursor.execute(sql)
# Выполнится: SELECT * FROM employees WHERE employee_id = 1 OR 1=1
# Злоумышленник получит все записи.
Безопасный код
user_input = input("Введите ID сотрудника: ")
cursor.execute(
"SELECT * FROM employees WHERE employee_id = %s",
(user_input,)
)
# Значение передаётся отдельно от SQL и безопасно экранируется.
📊 Сравнение в таблице
| Аспект | Старый подход | Новый подход |
|---|---|---|
| Закрытие соединения | Вручную connection.close() | Автоматически через with |
| Закрытие курсора | Вручную cursor.close() | Автоматически через with |
| Обработка ошибок | Требует try ... finally | Работает внутри with |
| Подстановка значений | f-string / конкатенация (опасно) | Плейсхолдеры %s / %(name)s |
| Читаемость | Больше вспомогательного кода | Компактный и понятный код |
⚠️ Проверить по документации: в некоторых библиотеках и ORM (например, SQLAlchemy 2.x, psycopg) синтаксис плейсхолдеров отличается. В PostgreSQL обычно используется
%s в psycopg2 или $1 в asyncpg. Всегда сверяйтесь с документацией конкретной библиотеки.