MySQL 系列:第4篇 增删改有章法(DML)

📅 2026/6/16 10:19:11
MySQL 系列:第4篇 增删改有章法(DML)
IT策士 10余年一线大厂经验专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章助你少走弯路。前面的文章我们学会了建库、建表、选类型相当于盖好了房子、规划了房间。今天终于要往里面“放家具”和“挪家具”了——这就是 DMLData Manipulation Language包含INSERT、UPDATE、DELETE三大操作。别小看这三板斧用不好轻则数据错乱重则误删全表。我们将用 Python 逐一拆解并给出生产环境下的安全准则与性能优化技巧。1. INSERT把数据塞进去1.1 单行插入最基础的姿势importmysql.connector connmysql.connector.connect(host127.0.0.1,port3306,userroot,passwordMyNewPass123!,databaseshop)cursorconn.cursor()# 先准备好一张产品表复用第3篇的结构cursor.execute( CREATE TABLE IF NOT EXISTS products(idINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200)NOT NULL UNIQUE, price DECIMAL(10,2)NOT NULL, stock INT DEFAULT0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)ENGINEInnoDB)# 单行插入sqlINSERT INTO products (title, price, stock) VALUES (%s, %s, %s)cursor.execute(sql,(Python 入门书,59.90,100))conn.commit()print(f✅ 插入成功新 ID {cursor.lastrowid})预期输出要点参数化查询%s是占位符不要用字符串拼接防止 SQL 注入。必须 commitmysql-connector-python默认自动提交关闭忘记 commit 会导致数据丢失。1.2 批量插入效率提升百倍如果要插入 1000 条数据单条循环插入会产生 1000 次网络往返。用executemany一次性提交books[(Python 高级编程,79.00,50),(MySQL 实战,69.00,80),(Redis 深度历险,49.00,120),(Linux 私房菜,89.00,30),]sqlINSERT INTO products (title, price, stock) VALUES (%s, %s, %s)cursor.executemany(sql, books)conn.commit()print(f✅ 批量插入 {cursor.rowcount} 条记录)预期输出性能对比实验不妨动手试试用time模块计时插入 10000 条数据单条循环 vsexecutemany的耗时可能相差几十倍。这就是批量操作的威力。1.3 存在即更新ON DUPLICATE KEY UPDATE当唯一键冲突时我们不想报错而是希望更新某些字段。例如同一本书再次入库时累加库存sql INSERT INTO products(title, price, stock)VALUES(%s, %s, %s)ON DUPLICATE KEY UPDATE stockstock VALUES(stock) cursor.execute(sql,(Python 入门书,59.90,50))conn.commit()print(f✅ 库存已累加受影响行数: {cursor.rowcount})预期输出注意如果冲突发生且执行了更新rowcount返回 2如果是全新插入返回 1。可据此判断操作类型。1.4 INSERT IGNORE冲突时静默跳过INSERT IGNORE INTO ...遇到主键或唯一键冲突时直接忽略不报错也不更新。cursor.execute(INSERT IGNORE INTO products (title, price, stock) VALUES (%s, %s, %s),(Python 入门书,59.90,10))conn.commit()print(f受影响行数: {cursor.rowcount})# 0因为已存在2. UPDATE修改已有数据2.1 基础语法与 Python 示例UPDATE 表名 SET 列1值1, 列2值2 WHERE 条件;无 WHERE 的 UPDATE 会修改全表这是生产事故的高发区。来看一个安全示例# 将 id1 的商品价格上调 10%cursor.execute(UPDATE products SET price price * 1.1 WHERE id %s,(1,))conn.commit()print(f✅ 更新了 {cursor.rowcount} 行)2.2 安全准则先查后改在大批量更新前最好先用相同 WHERE 条件执行 SELECT确认受影响的行数# 安全三步走查看 → 确认 → 更新cursor.execute(SELECT COUNT(*) FROM products WHERE stock 10)countcursor.fetchone()[0]print(f⚠️ 即将清空 {count} 件低库存商品的库存是否继续)# 实际生产中这里应该有确认逻辑ifcount100: cursor.execute(UPDATE products SET stock 0 WHERE stock 10)conn.commit()print(f✅ 已将 {cursor.rowcount} 件商品库存置 0)2.3 利用 LIMIT 防止误更新大量数据UPDATE products SET stock0WHERE stock10LIMIT10;分批更新每次只影响少量行降低事故爆炸半径。3. DELETE删数据是件严肃的事3.1 DELETE 基础同样无 WHERE 会清空整个表。建议开启 MySQL 的--safe-updates模式或设置sql_safe_updates1在没带 WHERE 或 LIMIT 时拒绝执行。# 删除 id5 的记录cursor.execute(DELETE FROM products WHERE id %s,(5,))conn.commit()print(f✅ 删除了 {cursor.rowcount} 行)3.2 软删除 vs 硬删除生产环境很少物理删除数据通常采用软删除增加is_deleted字段标记为 1。ALTER TABLE products ADD COLUMN is_deleted TINYINT DEFAULT0;删除操作变为cursor.execute(UPDATE products SET is_deleted 1 WHERE id %s,(3,))conn.commit()所有查询后面追加WHERE is_deleted 0数据可恢复符合审计要求。3.3 TRUNCATE快速清空表TRUNCATE TABLE products相当于DROP CREATE速度极快不记日志因此无法回滚且重置自增 ID。适合清空测试数据生产慎用。4. 批量数据导入导出思路实际工作中经常需要将 CSV 或外部数据导入 MySQL或者导出备份。这里给出 Python 实现方案。4.1 从 CSV 文件导入假设有products.csv文件title,price,stock 机器学习,79.00,40 深度学习,89.00,30importcsv with open(products.csv,r,encodingutf-8)as f: readercsv.DictReader(f)data[(row[title], row[price], row[stock])forrowinreader]sqlINSERT INTO products (title, price, stock) VALUES (%s, %s, %s)cursor.executemany(sql, data)conn.commit()print(f✅ 从 CSV 导入了 {cursor.rowcount} 行)4.2 导出到 CSVcursor.execute(SELECT title, price, stock FROM products WHERE is_deleted 0)rowscursor.fetchall()with open(export_products.csv,w,newline,encodingutf-8)as f: writercsv.writer(f)writer.writerow([title,price,stock])writer.writerows(rows)print(✅ 导出完成)更高效的方式是使用 MySQL 自带的SELECT INTO OUTFILE但需服务器文件权限。Python 方案更灵活。5. 事务在 DML 中的角色DML 操作通常在事务中执行保证原子性要么全成功要么全回滚。Python 默认需要在 DML 后显式commit()否则关闭连接时自动回滚。try: cursor.execute(UPDATE products SET stock stock - 10 WHERE id 1)cursor.execute(UPDATE products SET stock stock 10 WHERE id 2)conn.commit()except Exception as e: conn.rollback()print(f❌ 事务回滚: {e})这是实现转账、库存扣减等业务的基础。后续文章会深入讲解事务隔离级别与锁。6. 动手试试搭建一个小型进货系统模拟一个图书进货流程插入新书如果已存在则累加库存。更新库存时如果更新后库存为负则回滚使用 Python 检查。将所有价格低于 60 元的书打 9 折。导出当前全部库存到 CSV。你可以基于前面的products表练习参考代码框架如下# 进货book(Python 入门书,59.90,20)cursor.execute( INSERT INTO products(title, price, stock)VALUES(%s,%s,%s)ON DUPLICATE KEY UPDATE stockstock VALUES(stock), book)# 安全扣减库存cursor.execute(SELECT stock FROM products WHERE id 1)stockcursor.fetchone()[0]ifstock5: cursor.execute(UPDATE products SET stock stock - 5 WHERE id 1)conn.commit()else: print(库存不足)# 打折cursor.execute(UPDATE products SET price price * 0.9 WHERE price 60)conn.commit()# 导出代码见前7. 总结DML 看似简单却是日常工作中最容易出事故的地方。记住三条铁律增使用参数化批量用executemany冲突用ON DUPLICATE KEY。改永远先 SELECT 确认范围大量更新加 LIMIT 分批。删优先软删除硬删除前务必三思开启safe-updates保平安。下一篇我们将进入SELECT 查询的艺术学习如何从海量数据中精准、高效地取出想要的内容。下次见想了解更多还可以去各个平台搜索「IT策士」一起升级 IT 思维