MySQL Insert в Python
Узнайте, как вставлять одиночные и множественные строки, получать auto-increment ID в MySQL из Python с помощью mysql-connector-python.
Чтобы вставить данные в таблицу MySQL из Python, необходимы три вещи: активное соединение, параметризованный SQL-запрос и вызов commit(). В этой главе рассматриваются вставка одиночной строки, массовая вставка с помощью executemany(), получение автоматически сгенерированного ID новой строки, обработка дубликатов с помощью ON DUPLICATE KEY UPDATE, а также типичные ошибки, с которыми сталкиваются начинающие.
Предварительные требования
Перед запуском любого примера из этой главы убедитесь, что у вас есть:
- Python 3.x и работающий сервер MySQL
- Установленный
mysql-connector-python:
pip install mysql-connector-python- Уже созданная база данных и таблица
customers— см. MySQL Create Database и MySQL Create Table, если вам нужно настроить их.
В примерах используется следующее определение таблицы:
CREATE TABLE IF NOT EXISTS customers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address VARCHAR(255)
);Подключение к MySQL
Каждая операция начинается с объекта соединения. Передайте хост, учётные данные и имя базы данных в mysql.connector.connect(), затем создайте курсор:
import mysql.connector
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()Объект cursor отправляет SQL-запросы серверу. Повторно используйте одно соединение для нескольких запросов вместо того, чтобы подключаться заново каждый раз.
Вставка одной строки
Используйте SQL-оператор INSERT INTO с заполнителями %s и передавайте фактические значения в виде кортежа. Никогда не формируйте строку запроса с помощью форматирования % или f-строк Python — это открывает код для SQL-инъекций.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
val = ("John", "Highway 21")
mycursor.execute(sql, val)
mydb.commit()
print(mycursor.rowcount, "record inserted.")
except Error as e:
print(f"Error: {e}")
mydb.rollback()
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Ключевые моменты:
%s— это синтаксис заполнителя дляmysql-connector-pythonнезависимо от типа данных столбца (строки, целые числа, даты — всё использует%s).mydb.commit()обязателен — без него вставка не будет записана на диск. MySQL оборачивает DML-операторы в неявные транзакции; необходимо выполнить commit для их завершения.mydb.rollback()в блокеexceptотменяет любые частичные изменения, если оператор завершился ошибкой.
Получение Auto-Increment ID
После успешной вставки mycursor.lastrowid содержит первичный ключ AUTO_INCREMENT, который MySQL присвоил новой строке:
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
val = ("Alice", "Maple Street 7")
mycursor.execute(sql, val)
mydb.commit()
print("Inserted row ID:", mycursor.lastrowid)
except Error as e:
print(f"Error: {e}")
mydb.rollback()
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Пример вывода:
Inserted row ID: 1Значение равно 0, если таблица не имеет столбца AUTO_INCREMENT. Используйте lastrowid для немедленной ссылки на новую запись в связанных таблицах (например, для вставки соответствующей строки в таблицу orders).
Вставка нескольких строк
executemany() отправляет список кортежей со значениями за один запрос к серверу, что значительно эффективнее, чем вызов execute() в цикле:
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "INSERT INTO customers (name, address) VALUES (%s, %s)"
vals = [
("Peter", "Lowstreet 4"),
("Amy", "Apple St 652"),
("Hannah", "Mountain 21"),
("Michael", "Valley 345"),
("Sandy", "Ocean Blvd 2"),
("Betty", "Green Grass 1"),
("Richard", "Sky St 331"),
("Susan", "One Way 98"),
("Vicky", "Yellow Garden 2"),
("Ben", "Park Lane 38"),
("William", "Central St 954"),
("Chuck", "Main Road 989"),
("Viola", "Sideway 1633"),
]
mycursor.executemany(sql, vals)
mydb.commit()
print(mycursor.rowcount, "records inserted.")
except Error as e:
print(f"Error: {e}")
mydb.rollback()
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Пример вывода:
13 records inserted.mycursor.rowcount после executemany() возвращает общее количество строк, затронутых по всем кортежам.
Когда предпочесть executemany() вместо цикла
| Подход | Запросы к серверу | Когда использовать |
|---|---|---|
execute() в цикле | Один на строку | Строки зависят от результатов друг друга |
executemany() | Один всего | Массовая вставка независимых строк |
Для очень больших наборов данных (десятки тысяч строк) рассмотрите разбиение на пакеты по 500–1000 строк, чтобы единичный сбой не отменял всю операцию.
Вставка без ошибок при дубликатах
Если в таблице есть ограничение UNIQUE и вы пытаетесь вставить строку, которая уже существует, MySQL выдаёт ошибку дублирующегося ключа. Два распространённых способа избежать этого:
INSERT IGNORE
INSERT IGNORE молча пропускает строки, нарушающие ограничение уникальности:
sql = "INSERT IGNORE INTO customers (name, address) VALUES (%s, %s)"
mycursor.execute(sql, ("John", "Highway 21"))
mydb.commit()
print(mycursor.rowcount, "row(s) affected") # 0 if row already existedON DUPLICATE KEY UPDATE
ON DUPLICATE KEY UPDATE выполняет обновление, когда уникальный ключ уже существует, превращая оператор в «upsert» (вставка или обновление):
sql = """
INSERT INTO customers (name, address)
VALUES (%s, %s)
ON DUPLICATE KEY UPDATE address = VALUES(address)
"""
mycursor.execute(sql, ("John", "New Address 5"))
mydb.commit()
# rowcount is 1 for insert, 2 for update, 0 if row existed but was unchanged
print(mycursor.rowcount, "row(s) affected")Используйте ON DUPLICATE KEY UPDATE, когда нужно хранить актуальное значение вне зависимости от того, является строка новой или существующей.
Вставка данных из словаря
Когда данные поступают в виде списка словарей (например, из разобранного JSON-ответа), можно динамически формировать SQL и значения:
import mysql.connector
from mysql.connector import Error
customers = [
{"name": "Eva", "address": "Elm Street 3"},
{"name": "Oscar", "address": "Birch Lane 9"},
]
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "INSERT INTO customers (name, address) VALUES (%(name)s, %(address)s)"
mycursor.executemany(sql, customers)
mydb.commit()
print(mycursor.rowcount, "records inserted.")
except Error as e:
print(f"Error: {e}")
mydb.rollback()
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Именованные заполнители (%(name)s) делают намерение более явным при работе со словарями и снижают риск неправильного выравнивания позиционных значений.
Распространённые ошибки
Забыть commit() — вставка как будто выполняется (без ошибок), но данные не сохраняются. Всегда вызывайте mydb.commit() после DML-операторов.
Формирование SQL через строковое форматирование — использование f-строк или форматирования % для встраивания пользовательского ввода является наиболее частым источником SQL-инъекций. Всегда передавайте значения вторым аргументом в execute().
Незакрытые соединения — используйте блок finally (или менеджер контекста), чтобы гарантировать вызов cursor.close() и mydb.close().
Использование INSERT, когда таблица ещё не создана — вы получите ошибку Table 'mydatabase.customers' doesn't exist. Сначала выполните CREATE TABLE или проверьте с помощью SHOW TABLES. См. MySQL Create Table.
Что делать дальше
После вставки строк вам, как правило, потребуется их прочитать. См. MySQL Select для запросов SELECT, MySQL Where для фильтрации и MySQL Update для изменения существующих строк.