Урок 80. MySQL и Python

📁 Блок: Базы данных ⏱️ Время изучения: ~90 мин 🎯 Сложность: Средняя
#close #for #in

⚡ Кратко: суть темы

MySQL и Python — подключаемся к реляционной базе данных из Python через библиотеку PyMySQL, выполняем SQL-запросы и безопасно обрабатываем результаты.

  • Устанавливаем pip install pymysql и открываем соединение через pymysql.connect(...).
  • Через объект cursor выполняем запросы методом execute(), а результаты читаем через fetchone(), fetchmany(), fetchall() или цикл for row in cursor.
  • Параметры запроса всегда передаём отдельно от текста SQL — через %s или %(name)s — чтобы избежать SQL-инъекций.
  • Для надёжности используем with connection.cursor() as cursor и обрабатываем ошибки через try ... except pymysql.MySQLError.

Что запомнить: никогда не подставляй пользовательский ввод напрямую в строку SQL — только параметризованные запросы.

Частая ошибка: забыть запятую в кортеже из одного значения: (value,) обязательна.

📖 Зачем нужны базы данных

Когда программы растут, данные нужно хранить вне кода: о товарах, пользователях, заказах, сообщениях и т.д. Базы данных позволяют:

  • хранить структурированные данные вне программы;
  • быстро искать, обновлять и удалять записи;
  • работать с большими объёмами без загрузки всего в память;
  • обеспечить многопользовательский доступ и защиту данных;
  • делать программы надёжнее и масштабируемее.

MySQL — одна из самых популярных реляционных СУБД. В этом уроке мы научимся подключаться к ней из Python, выполнять запросы, получать результаты и защищать код от типичных ошибок.

🔌 Библиотеки для работы с MySQL

БиблиотекаОсобенности
PyMySQLПростая, полностью на Python, работает стабильно на всех ОС
mysql-connector-pythonОфициальная библиотека от MySQL
MySQLdb / mysqlclientОчень быстрая, но сложнее в установке (особенно на Windows)

Мы будем использовать PyMySQL:

pip install pymysql

🔑 Подключение к базе данных

Чтобы подключиться, импортируем модуль и вызываем pymysql.connect() с параметрами подключения:

import pymysql

connection = pymysql.connect(
    host="localhost",        # адрес сервера базы данных
    user="root",             # имя пользователя
    password="yourpassword", # пароль
    database="yourdatabase", # название базы данных (необязательно)
    charset="utf8mb4",       # кодировка соединения (рекомендуется для кириллицы)
)

Параметры можно хранить в словаре и распаковывать через ** — это удобно, если подключений несколько или конфигурация читается из файла:

import pymysql

config = {
    "host": "ich-db.edu.itcareerhub.de",
    "user": "ich1",
    "password": "password",
    "database": "hr",
}

connection = pymysql.connect(**config)

После создания соединения можно проверить его состояние:

if connection.open:
    print("Connection successful!")

Открытые соединения занимают ресурсы сервера, поэтому соединение нужно закрывать:

connection.close()

🖱️ Курсор: выполнение запросов

Курсор — это объект, через который отправляются SQL-запросы и получаются результаты.

cursor = connection.cursor()
cursor.execute("SELECT * FROM departments")
  • cursor.execute(sql) отправляет SQL-запрос к базе данных.
  • SQL-запрос передаётся строкой.
  • Можно выполнять любые запросы: SELECT, INSERT, UPDATE, DELETE и др.
  • После каждого нового запроса старые результаты очищаются.
  • При ошибке в запросе выбрасывается исключение.

После использования курсор закрывают вручную:

cursor.close()

📥 Получение результатов

После SELECT данные остаются в курсоре. Для чтения используются методы:

МетодЧто делает
fetchone()Возвращает одну следующую строку или None
fetchmany(size)Возвращает заданное число строк
fetchall()Возвращает все оставшиеся строки
for row in cursorИтерируется по строкам как по итератору

Курсор сдвигается после каждого чтения: повторный вызов fetchall() вернёт пустую коллекцию, если строки уже были считаны.

🛡️ Параметризованные запросы

Никогда нельзя подставлять значения пользователя напрямую в строку SQL — это приводит к SQL-инъекциям. Вместо этого используют плейсхолдеры %s и передают значения отдельно:

cursor.execute(
    "SELECT * FROM employees WHERE department_id = %s OR salary > %s",
    (60, 20000)
)
for row in cursor:
    print(row)

Если значение одно, кортеж всё равно нужен — не забудьте запятую:

cursor.execute(
    "SELECT * FROM employees WHERE department_id = %s",
    (100,)  # обязательно запятая!
)

Именованные параметры

Для большей читаемости можно использовать именованные плейсхолдеры %(name)s и словарь:

cursor.execute(
    "SELECT * FROM employees WHERE department_id = %(dep_id)s OR salary > %(min_salary)s",
    {"min_salary": 20000, "dep_id": 60}
)
for row in cursor:
    print(row)

⚠️ Обработка ошибок

При работе с базой могут возникать ошибки подключения, неверный SQL, отсутствие таблицы и т.д. Чтобы программа не падала, используем try ... except:

import pymysql

try:
    connection = pymysql.connect(
        host="ich-db.edu.itcareerhub.de",
        user="root",
        password="wrong_password",
        database="test"
    )
    print("Connected!")
except pymysql.MySQLError as e:
    print("Connection error:", e)

Базовый класс всех исключений PyMySQL — pymysql.MySQLError. Часто используются также pymysql.ProgrammingError (ошибки SQL) и pymysql.OperationalError (проблемы соединения).

🧰 Контекстный менеджер with

Конструкция with автоматически закрывает соединение и курсор, даже если внутри блока произошла ошибка:

with pymysql.connect(
    host="ich-db.edu.itcareerhub.de",
    user="ich1",
    password="password",
    database="hr"
) as connection:
    with connection.cursor() as cursor:
        cursor.execute("SELECT * FROM employees")
        for row in cursor:
            print(row)

✨ Современные практики

⚠️ Проверить по документации: рекомендации ниже выходят за рамки исходной лекции. В рабочих проектах обычно используют переменные окружения, python-dotenv и ORM (например, SQLAlchemy).
  • Храните пароли и логины в переменных окружения, а не в коде.
  • Для локальной разработки удобна библиотека python-dotenv: положите секреты в файл .env и загрузите через load_dotenv().
  • Никогда не собирайте SQL через f-string или конкатенацию строк с пользовательским вводом.
  • Используйте with для автоматического закрытия ресурсов.
  • Именуйте конфигурационные словари в UPPER_CASE, если они константы (PEP 8).