ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

PyMySQL操作MySQL数据库的全面指南

PyMySQL操作MySQL数据库的全面指南 1. 为什么需要PyMySQL操作MySQL十年前我刚接触Python操作数据库时用的还是MySQLdb模块。直到2013年遇到一个Python3项目才发现这个经典库居然不支持Python3当时在GitHub上发现的PyMySQL如今已成为Python连接MySQL最主流的方案之一。PyMySQL纯Python实现的特性让它具备了极好的跨平台兼容性从Windows到Linux再到macOS都能完美运行。相比需要编译安装的MySQLdbPyMySQL只需一句pip install就能使用这对新手特别友好。我在实际项目中还发现PyMySQL对Unicode的支持更加完善处理中文数据时很少出现乱码问题。2. 环境准备与基础配置2.1 安装与版本选择当前PyMySQL的最新稳定版本是1.0.2我建议使用这个版本而非开发版。安装时要注意Python版本兼容性# 基础安装 pip install pymysql # 指定版本安装 pip install pymysql1.0.2注意如果同时安装了MySQLdb和PyMySQL可能会产生冲突。建议使用虚拟环境隔离。2.2 连接池配置实战在高并发场景下我强烈推荐使用连接池。这是我常用的配置方案import pymysql from pymysql import pools # 创建连接池 pool pools.PooledDB( creatorpymysql, maxconnections20, # 最大连接数 mincached5, # 初始化时创建的连接数 hostlocalhost, userroot, passwordyourpassword, databasetest, charsetutf8mb4, cursorclasspymysql.cursors.DictCursor )这个配置在我的Web项目中可以支撑500的QPS关键参数说明maxconnections根据服务器内存调整一般每连接占用5-10MBcharset一定要用utf8mb4才能支持完整的Unicode包括emojiDictCursor会让返回结果以字典形式呈现操作更方便3. CRUD操作全解析3.1 防注入的SQL执行规范先看一个典型的错误示范# 危险SQL注入漏洞 sql SELECT * FROM users WHERE name%s % username cursor.execute(sql)正确的参数化查询应该是# 安全写法 sql SELECT * FROM users WHERE name%s cursor.execute(sql, (username,))我在代码审计中发现90%的SQL注入漏洞都源于字符串拼接。PyMySQL的execute()方法会自动处理参数转义但必须确保使用元组传参。3.2 事务处理最佳实践这是我从线上事故中总结的事务模板try: conn pool.connection() with conn.cursor() as cursor: # 操作1 cursor.execute(UPDATE accounts SET balancebalance-100 WHERE user_id1) # 操作2 cursor.execute(UPDATE accounts SET balancebalance100 WHERE user_id2) # 显式提交 conn.commit() except Exception as e: conn.rollback() print(f事务失败: {e}) finally: conn.close()关键点一定要在try块外获取连接避免commit/rollback时连接已关闭with语句确保cursor自动关闭必须显式调用commit()PyMySQL默认不自动提交4. 高级特性深度应用4.1 流式查询处理海量数据当查询结果超过内存容量时可以使用流式查询conn pymysql.connect(hostlocalhost, userroot, password, databaselarge_db, cursorclasspymysql.cursors.SSCursor) # 关键在这里 try: with conn.cursor() as cursor: cursor.execute(SELECT * FROM huge_table) while True: row cursor.fetchone() if not row: break # 处理单行数据 finally: conn.close()SSCursorServer Side Cursor不会一次性加载所有结果而是从服务器分批获取。我在处理千万级数据表时这种方式将内存占用从10GB降到了100MB以下。4.2 批量操作性能优化对比单条插入和批量插入的性能差异# 低效写法1000次网络往返 for i in range(1000): cursor.execute(INSERT INTO test VALUES (%s), (i,)) # 高效写法1次网络往返 data [(i,) for i in range(1000)] cursor.executemany(INSERT INTO test VALUES (%s), data)实测结果单条插入1000条1.2秒批量插入1000条0.05秒提示大批量插入时建议每5000-10000条提交一次避免产生过大的事务。5. 生产环境问题排查5.1 连接泄露检测方案这是我编写的连接泄露检测装饰器import functools import pymysql def check_connection_leak(func): functools.wraps(func) def wrapper(*args, **kwargs): # 获取当前连接数 conn pymysql.connect(hostlocalhost, userroot) with conn.cursor() as cur: cur.execute(SHOW STATUS LIKE Threads_connected) before cur.fetchone()[Value] result func(*args, **kwargs) # 再次检查 with conn.cursor() as cur: cur.execute(SHOW STATUS LIKE Threads_connected) after cur.fetchone()[Value] if after before 2: # 允许2个误差 print(f警告可能的连接泄露调用前{before}调用后{after}) conn.close() return result return wrapper5.2 超时设置黄金法则这些超时参数必须配置conn pymysql.connect( hostlocalhost, connect_timeout5, # 连接超时 read_timeout30, # 查询超时 write_timeout30, # 写入超时 # ... )经验值参考内网环境connect_timeout3read/write_timeout10公网环境connect_timeout5read/write_timeout30大数据操作单独设置execute()的timeout参数6. 与ORM框架的协作6.1 SQLAlchemy集成技巧在Flask-SQLAlchemy中配置PyMySQLfrom flask import Flask from flask_sqlalchemy import SQLAlchemy app Flask(__name__) app.config[SQLALCHEMY_DATABASE_URI] \ mysqlpymysql://user:passwordlocalhost/dbname?charsetutf8mb4 app.config[SQLALCHEMY_ENGINE_OPTIONS] { pool_size: 20, pool_recycle: 3600, pool_pre_ping: True } db SQLAlchemy(app)关键参数说明pool_recycle避免MySQL默认8小时断开连接的问题pool_pre_ping执行前检查连接有效性charset必须指定否则中文会出现乱码6.2 Django配置要点在settings.py中配置DATABASES { default: { ENGINE: django.db.backends.mysql, OPTIONS: { read_default_file: /path/to/my.cnf, init_command: SET default_storage_engineINNODB, charset: utf8mb4, }, } }然后在my.cnf中添加[client] database dbname user user password password host 127.0.0.1 port 3306 default-character-set utf8mb4这种分离配置的方式更安全特别是使用版本控制时。
返回列表