python连接数据库mysql
用 Python 连 MySQL,连接最省事的数据办法是装 装完之后,数据连库的连接代码短得有点不像话: 注意那个 连接对象有个坑:默认不自动提交。你执行完 INSERT、UPDATE 之后,数据其实还在事务里,程序一关就没了。要么手动 再说 cursor 的类型。默认返回元组,你得靠下标取字段,代码可读性差。换成 字段名直接当 key 用,调试的时候一眼就能看出数据长什么样。 批量插入是个高频场景。一条条 execute 再 commit,几千条数据能跑到天荒地老。用 这里的 连接池的事也得提一句。每次请求都新建连接、用完就关,在并发稍微高一点的场景下开销很明显。DBUtils 里的 注意最后那个 字符集统一用 最后说个实际经历。有次线上服务查 MySQL 偶尔超时,代码逻辑查了半天没问题。后来发现是连接没设 PyMySQL 的文档不算详细,但源码不长,遇到奇怪的问题直接翻源码往往比搜半天 Stack Overflow 快。数据库连接这事,代码写对只是及格,把超时、事务、连接池这些边角处理干净,才算真正能用。PyMySQL。这东西纯 Python 实现,连接不用编译,数据pip 一行就搞定。连接我见过不少人一上来就折腾 mysql-connector-python,数据结果被版本兼容性搞得头大——PyMySQL 反而稳得多。连接pip install pymysqlimport pymysql conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='your_password', database='test_db', charset='utf8mb4' ) cursor = conn.cursor() cursor.execute("SELECT id, name FROM users WHERE age > %s", (18,)) rows = cursor.fetchall() for row in rows: print(row) cursor.close() conn.close()%s 占位符。PyMySQL 用 %s 做参数化查询,数据跟 sqlite3 的连接 ? 不一样。有人图省事直接拼字符串,数据比如 "SELECT * FROM users WHERE name = '" + name + "'",连接这就是数据在给 SQL 注入留后门。参数化查询不光安全,连接批量插入的时候速度也快不少。conn.commit(),要么在 connect 的时候加 autocommit=True。我自己的习惯是显式 commit,这样事务边界清楚,出了错也好回滚。pymysql.cursors.DictCursor 就舒服多了:conn = pymysql.connect( ..., cursorclass=pymysql.cursors.DictCursor ) cursor = conn.cursor() cursor.execute("SELECT id, name FROM users LIMIT 1") row = cursor.fetchone() print(row['name'])executemany 加上事务,速度差出两个数量级:data = [(1, 'Alice'), (2, 'Bob'), (3, 'Carol')] try: with conn.cursor() as cursor: cursor.executemany( "INSERT INTO users (id, name) VALUES (%s, %s)", data ) conn.commit() except Exception as e: conn.rollback() print("插入失败:", e)with 语句只管 cursor 的关闭,不会自动提交事务。commit 和 rollback 得自己写。很多人以为 with 一包就万事大吉,结果数据没进去,查半天查不出原因。PooledDB 可以解决这个问题:from dbutils.pooled_db import PooledDB import pymysql pool = PooledDB( creator=pymysql, maxconnections=10, host='127.0.0.1', user='root', password='your_password', database='test_db', charset='utf8mb4' ) conn = pool.connection() cursor = conn.cursor() cursor.execute("SELECT COUNT(*) FROM users") print(cursor.fetchone()) cursor.close() conn.close() # 归还连接到池,不是真正关闭conn.close(),在连接池里它的含义是“还回去”,不是断开 TCP。这个语义差异第一次用容易懵。utf8mb4,别用 utf8。MySQL 的 utf8 是残缺实现,存 emoji 会报错。utf8mb4 才是完整的四字节 UTF-8。建库建表的时候都指定好,连接时也带上,省得后面出乱码再回头改。connect_timeout 和 read_timeout,网络抖动的时候线程就挂在那里等。加上这两个参数之后,至少能快速失败、快速重试,不至于把整个请求拖死。conn = pymysql.connect( ..., connect_timeout=5, read_timeout=10, write_timeout=10 )