news 2026/9/27 16:10:55

用 pymysql 连接数据库:从 connect 到 commit 的完整操作指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 pymysql 连接数据库:从 connect 到 commit 的完整操作指南

1. 为什么你的 pymysql 一跑就报错:先看清 connect 到 commit 的链路

很多 Python 开发者第一次用 pymysql 连数据库,代码看着没问题,运行起来却报Access denied、Unknown database,或者更隐蔽的——数据明明插进去了,重新查询却什么都没有。问题往往不在 SQL 本身,而在于没搞清楚 pymysql 的四个核心环节:connect 建立连接、cursor 创建游标、execute 执行语句、commit 提交事务。

pymysql 是纯 Python 实现的 MySQL 客户端库,不需要编译 C 扩展,pip install pymysql就能用。它适合谁?适合做数据采集落库、后台脚本、Flask/Django 之外的轻量数据操作,以及需要快速验证 SQL 逻辑的场景。你可以把它理解成一座桥:Python 程序在桥这头,MySQL 服务在桥那头,connect 是搭桥,cursor 是桥上的传送带,execute 是把货物放上传送带,commit 则是按下“确认收货”——不按,货就一直在半路。

我试过在本地起一个 MySQL 8.0,用 pymysql 走一遍建表、插入、查询、更新、删除的完整闭环,中间踩过字符集和事务的坑。下面把可复制的配置骨架和验证动作拆开讲,你跟着敲一遍就能独立跑通。

2. 前置准备:装库、建库、确认连接四要素

在写代码之前,先把环境理清楚。pymysql 的安装很简单:

pip install pymysql

如果你用的是虚拟环境,先激活再装。装完可以用pip show pymysql确认版本,一般 1.1.x 就够用。

接着确认 MySQL 服务在跑,并且你有一个可用的库。这里假设你已经建好一个名为ss的数据库。如果没有,用命令行或客户端执行:

CREATE DATABASE ss DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

字符集建议统一用utf8mb4,否则中文和 emoji 容易出问题。连接四要素必须写对:host、user、password、database。密码字段在 pymysql 里既可以写password也可以写passwd,两者等价,但别拼错。端口默认 3306,如果改过要显式指定port。

注意:连接信息不要硬编码在业务代码里,正式项目建议走环境变量或配置文件。本文为了演示直观,直接写在代码中。

3. 可复制配置:connect、cursor、execute、commit 四步骨架

先给一个最小可运行骨架,把四个环节串起来。这段代码的作用是连接数据库、查询 MySQL 版本,验证链路是否通:

import pymysql # 第一步:connect 建立连接 conn = pymysql.connect( host='localhost', user='root', password='123456', database='ss', port=3306, charset='utf8mb4' ) try: # 第二步:cursor 创建游标 cursor = conn.cursor() # 第三步:execute 执行 SQL cursor.execute('SELECT VERSION()') # 取回单条结果 data = cursor.fetchone() print('MySQL 版本:', data) finally: # 第四步:关闭游标和连接 cursor.close() conn.close()

运行后如果打印出类似MySQL 版本: ('8.0.36',),说明 connect、cursor、execute 三个环节都通了。这里没有写 commit,因为查询不改变数据状态,不需要提交。

接下来建一张表,把 commit 加进来。表名和字段名建议用反引号包裹,避免和关键字冲突:

import pymysql conn = pymysql.connect( host='localhost', user='root', password='123456', database='ss', charset='utf8mb4' ) try: cursor = conn.cursor() sql = ''' CREATE TABLE IF NOT EXISTS `tast` ( `first_name` VARCHAR(10) PRIMARY KEY, `last_name` VARCHAR(10), `age` INT(5), `sex` VARCHAR(6), `income` INT(30) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ''' cursor.execute(sql) # 关键:DDL 之后也要 commit,否则部分场景下不生效 conn.commit() print('建表成功') except Exception as e: conn.rollback() print('建表失败:', e) finally: cursor.close() conn.close()

这里有个容易忽略的点:CREATE TABLE属于 DDL,在 MySQL 里默认是自动提交的,但显式写conn.commit()更稳妥,也养成习惯。异常捕获里加conn.rollback(),出错时回滚,避免留下半成品状态。

4. 增删改查全流程:executemany 批量插入与事务提交验证

建好表后,先插入数据。单条插入用execute,多条插入用executemany,后者效率更高:

import pymysql conn = pymysql.connect( host='localhost', user='root', password='123456', database='ss', charset='utf8mb4' ) try: cursor = conn.cursor() sql = ''' INSERT INTO `tast` (`first_name`, `last_name`, `age`, `sex`, `income`) VALUES (%s, %s, %s, %s, %s) ''' params = ( ('a', 'joe', 21, 'm', 5000), ('b', 'jae', 22, 'f', 5000), ('c', 'jbe', 23, 'f', 5000), ('d', 'jvce', 24, 'm', 5000), ) rows = cursor.executemany(sql, params) conn.commit() print('影响行数:', rows) except Exception as e: conn.rollback() print('插入失败:', e) finally: cursor.close() conn.close()

executemany返回的是受影响的行数,这里应该是 4。注意参数用%s占位,不要用字符串拼接,否则会有 SQL 注入风险。

插入完成后,验证查询:

import pymysql conn = pymysql.connect( host='localhost', user='root', password='123456', database='ss', charset='utf8mb4' ) try: cursor = conn.cursor() cursor.execute('SELECT `first_name`, `age`, `income` FROM `tast` WHERE `sex` = %s', ('f',)) results = cursor.fetchall() for row in results: print(row) finally: cursor.close() conn.close()

fetchall()返回所有结果,fetchone()返回单条。如果查询结果为空,fetchone()返回None,别直接下标取值。

更新和删除同样遵循 execute + commit 的模式:

# 更新 cursor.execute('UPDATE `tast` SET `income` = %s WHERE `first_name` = %s', (8000, 'a')) conn.commit() # 删除 cursor.execute('DELETE FROM `tast` WHERE `first_name` = %s', ('d',)) conn.commit()

每次改动数据后都要 commit,否则当前连接关闭时改动会丢失。你可以做个实验:把 commit 注释掉,插入数据后关闭连接,再重新查询,会发现数据没进去——这就是事务未提交的典型表现。

5. 验证请求与成功结果:用一条查询确认闭环

完整的验证动作是这样:插入数据后,不关闭连接,直接在同一连接内查询,确认数据可见;然后关闭连接,重新建立连接再查一次,确认数据已持久化。

import pymysql def get_conn(): return pymysql.connect( host='localhost', user='root', password='123456', database='ss', charset='utf8mb4' ) # 第一次连接:插入并查询 conn = get_conn() cursor = conn.cursor() cursor.execute("INSERT INTO `tast` VALUES ('e', 'test', 30, 'm', 9000)") conn.commit() cursor.execute("SELECT COUNT(*) FROM `tast`") print('当前连接内行数:', cursor.fetchone()) cursor.close() conn.close() # 第二次连接:重新查询,验证持久化 conn2 = get_conn() cursor2 = conn2.cursor() cursor2.execute("SELECT COUNT(*) FROM `tast`") print('新连接行数:', cursor2.fetchone()) cursor2.close() conn2.close()

两次打印的行数一致,说明 commit 生效、数据已落盘。如果第二次查不到,八成是 commit 漏了,或者连接用了自动提交关闭的配置。

6. 本篇常见错排查:从报错信息定位到具体环节

下面这张表把高频报错和对应环节列出来,方便你对号入座:

报错信息可能原因排查动作
Access denied for user用户名或密码错核对 connect 的 user/password
Unknown database 'ss'库不存在或名字拼错执行SHOW DATABASES确认
Can't connect to MySQL server服务没起或 host/port 错检查 MySQL 进程和端口
插入后查不到数据漏了 commit在 execute 后加 conn.commit()
中文乱码字符集不统一connect 加 charset='utf8mb4',建库建表也用 utf8mb4
Commands out of sync上一个结果集没读完用 fetchall 读完或换新 cursor

还有一个隐蔽的坑:cursor和conn忘记关闭,长时间运行会耗尽连接数。建议用try/finally或上下文管理器。pymysql 的连接对象支持with语法,但游标需要手动管理,写法如下:

with pymysql.connect(host='localhost', user='root', password='123456', database='ss', charset='utf8mb4') as conn: with conn.cursor() as cursor: cursor.execute('SELECT 1') print(cursor.fetchone())

with块结束时会自动 commit(如果没异常)或 rollback(如果有异常),并关闭连接。这个写法能省掉不少样板代码。

如果你在排查连接或权限问题时需要更细的日志,可以在 connect 里加cursorclass=pymysql.cursors.DictCursor,让结果以字典返回,字段名一目了然,调试时更直观。

7. 把连接配置沉淀成可复用模块

跑通一次闭环后,建议把连接逻辑抽成函数或类,避免每次重复写四要素。一个简单的做法是用字典存配置,从环境变量读取:

import os import pymysql def get_connection(): return pymysql.connect( host=os.getenv('DB_HOST', 'localhost'), user=os.getenv('DB_USER', 'root'), password=os.getenv('DB_PASSWORD', '123456'), database=os.getenv('DB_NAME', 'ss'), charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor )

这样本地开发和线上部署只需改环境变量,代码不用动。配合with语法,一个完整的读写操作可以压缩到几行:

with get_connection() as conn: with conn.cursor() as cursor: cursor.execute('SELECT * FROM `tast` WHERE `age` > %s', (20,)) for row in cursor.fetchall(): print(row['first_name'], row['income'])

到这里,connect、cursor、execute、commit 四个环节你已经完整走了一遍。接下来可以试着把 SQL 换成自己的业务表,或者接入定时任务做批量落库。如果后续要接大模型做数据问答、或者把数据库操作封装成 Agent 工具,可以到 TaoToken 的模型对话页面先验证模型对 SQL 的理解能力,再决定怎么把 pymysql 的读写链路嵌进你的编码工作流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/27 16:06:48

[特殊字符] AI编程神器!Trae+Claude4.0让HarmonyOS开发效率飙升

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 15:58:03

Claude Code + CC-Switch 一键安装与快速上手:TaoToken 统一 Key 配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/27 15:44:55

2026大厂AI龙虾避坑指南:OpenClaw封装版实测合集与TaoToken配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华