news 2026/9/26 12:07:54

Python 与 MySQL 数据库交互:获取插入后的自增 ID 深度解析与 TaoToken 配置实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 与 MySQL 数据库交互:获取插入后的自增 ID 深度解析与 TaoToken 配置实战

1. 插入数据后拿不到自增 ID,问题到底出在哪

Python 与 MySQL 数据库交互时,获取插入后的自增 ID 是个高频需求:新增用户后要拿 user_id 去建权限记录,新增订单后要拿 order_id 去写日志,新增文章后要拿 article_id 去做重定向。这些场景都指向同一个动作——INSERT 成功后,把数据库生成的那个 AUTO_INCREMENT 值取回来。

但实际操作里,很多人会踩到几类坑:cursor.lastrowid 返回 None,以为驱动坏了;用了 executemany 批量插入,发现只拿到一个 ID;在连接池里多线程跑,担心拿到的 ID 是别人的;或者干脆用 SELECT LAST_INSERT_ID() 又写错会话,拿到上一次的旧值。

这篇聚焦 Python 通过 mysql-connector-python 或 PyMySQL 插入数据后获取 lastrowid 的完整链路,覆盖 cursor.lastrowid、SELECT LAST_INSERT_ID() 与 executemany 场景差异。同时给出一套可复制的 settings.json / config.toml 骨架,以及用 TaoToken 统一 Key 接入配置的方式,让数据库凭据和模型调用凭据都走同一套管理思路。适合正在写后端 CRUD、做数据同步脚本,或者刚接触 MySQL 自增主键的开发者。

2. 前置准备:TaoToken 统一 Key 与数据库凭据管理

在写代码之前,先把凭据管理这件事理清楚。很多教程让你把数据库密码硬编码在 Python 文件里,这在本地跑 demo 没问题,一旦进版本库就是事故。我的做法是:数据库连接参数放配置文件,模型调用凭据走 TaoToken 统一 Key,两者都不进代码。

TaoToken 在这里的角色是统一管理模型调用的 API Key。当你的 Python 脚本除了写 MySQL,还要调用大模型做数据清洗、字段补全、内容摘要时,把模型 Key 收敛到一处会省很多事。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api 。

先拿到 Key:进入控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,在 API Keys 页面 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 创建一个 Key。这个 Key 后面会写进配置文件,供脚本读取。

数据库这边,先建库建表。表必须有 AUTO_INCREMENT 主键,这是 lastrowid 能返回有意义值的前提:

CREATE DATABASE IF NOT EXISTS mydatabase DEFAULT CHARSET utf8mb4; USE mydatabase; CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL, registered_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB;

注意 ENGINE=InnoDB。MyISAM 虽然也支持 AUTO_INCREMENT,但事务和行锁行为不同,现代项目一律用 InnoDB。

3. 可复制配置:settings.json 与 config.toml 骨架

配置文件的作用是把「会变的东西」抽出来。下面给两份骨架,选你顺手的格式即可。

3.1 settings.json 骨架

{ "mysql": { "host": "127.0.0.1", "port": 3306, "user": "app_user", "password": "REPLACE_WITH_ENV_OR_SECRET", "database": "mydatabase", "charset": "utf8mb4", "autocommit": false, "connection_timeout": 10 }, "taotoken": { "base_url": "https://taotoken.net/api", "api_key": "REPLACE_WITH_YOUR_TAOTOKEN_KEY", "default_model": "claude-sonnet-4-5" } }

3.2 config.toml 骨架

[mysql] host = "127.0.0.1" port = 3306 user = "app_user" password = "REPLACE_WITH_ENV_OR_SECRET" database = "mydatabase" charset = "utf8mb4" autocommit = false connection_timeout = 10 [taotoken] base_url = "https://taotoken.net/api" api_key = "REPLACE_WITH_YOUR_TAOTOKEN_KEY" default_model = "claude-sonnet-4-5"

读取配置的代码,JSON 用内置 json,TOML 用 tomllib(Python 3.11+):

import json from pathlib import Path def load_settings(path: str = "settings.json") -> dict: with Path(path).open("r", encoding="utf-8") as f: return json.load(f) settings = load_settings() DB_CONFIG = settings["mysql"] TAOTOKEN_CONFIG = settings["taotoken"]

注意:配置文件里的 password 和 api_key 建议用环境变量覆盖,例如 os.environ.get("MYSQL_PASSWORD", settings["mysql"]["password"]),这样配置文件可以安全进仓库。

4. 核心链路:cursor.lastrowid 与 SELECT LAST_INSERT_ID()

4.1 安装驱动

pip install mysql-connector-python # 或者用 PyMySQL pip install pymysql

两者在 lastrowid 行为上基本一致,下面以 mysql-connector-python 为主,PyMySQL 的差异会单独标注。

4.2 单行插入并获取自增 ID

import mysql.connector def insert_user_and_get_id(db_config: dict, username: str, email: str): last_id = None conn = None cursor = None try: conn = mysql.connector.connect(**db_config) cursor = conn.cursor() sql = "INSERT INTO users (username, email) VALUES (%s, %s)" cursor.execute(sql, (username, email)) conn.commit() last_id = cursor.lastrowid print(f"插入成功,username={username}, id={last_id}") except mysql.connector.Error as err: print(f"插入失败: {err}") if conn and conn.is_connected(): conn.rollback() finally: if cursor: cursor.close() if conn and conn.is_connected(): conn.close() return last_id

关键点:cursor.lastrowid 在 cursor.execute() 之后即可读取,不必等 commit。但如果你在 commit 之前又执行了另一条 INSERT,lastrowid 会被覆盖成后一条的 ID。所以拿到 ID 后立刻存变量,别拖。

4.3 用 SELECT LAST_INSERT_ID() 作为对照

cursor.execute("INSERT INTO users (username, email) VALUES (%s, %s)", (username, email)) conn.commit() cursor.execute("SELECT LAST_INSERT_ID()") last_id = cursor.fetchone()[0]

LAST_INSERT_ID() 是连接级(session 级)的,不同连接互不干扰,所以并发下也是安全的。但它多一次往返查询,且必须在同一个连接里紧接着执行。cursor.lastrowid 本质上是驱动帮你把这次查询的结果缓存下来了,所以更省事。

4.4 executemany 的差异

这是最容易踩坑的地方。批量插入时:

rows = [("u1", "u1@example.com"), ("u2", "u2@example.com"), ("u3", "u3@example.com")] cursor.executemany("INSERT INTO users (username, email) VALUES (%s, %s)", rows) conn.commit() print(cursor.lastrowid) # 通常只返回第一行的 ID

mysql-connector-python 在 executemany 后,lastrowid 一般只反映第一行。如果你需要全部 ID,有几种策略:

策略做法适用场景
逐行插入循环 execute,每次取 lastrowid行数少,需要精确 ID
应用层生成主键用 UUID 替代自增分布式、需要预知 ID
插入后按条件查回用唯一字段 SELECT 回查有业务唯一键
依赖连续自增取首 ID 后按行数推算单连接、无并发、innodb_autoinc_lock_mode=0/1

最后一种最脆弱,不推荐。生产环境优先用「应用层生成主键」或「逐行插入」。

5. 验证请求:插入后 ID 校验的完整动作

拿到 ID 不代表对。写一个校验函数,用 ID 回查一次,确认数据真的落库且字段匹配:

def verify_user_by_id(db_config: dict, user_id: int): with mysql.connector.connect(**db_config) as conn: with conn.cursor(dictionary=True) as cursor: cursor.execute( "SELECT id, username, email, registered_at FROM users WHERE id = %s", (user_id,) ) row = cursor.fetchone() if row: print(f"校验通过: {row}") else: print(f"校验失败: 未找到 id={user_id}") return row

跑一遍完整流程:

if __name__ == "__main__": new_id = insert_user_and_get_id(DB_CONFIG, "alice", "alice@example.com") if new_id: verify_user_by_id(DB_CONFIG, new_id)

预期输出类似:

插入成功,username=alice, id=1 校验通过: {'id': 1, 'username': 'alice', 'email': 'alice@example.com', 'registered_at': datetime.datetime(...)}

如果校验返回 None,说明 ID 拿到了但数据没落库,八成是 commit 没执行或事务被回滚。

6. 本篇常见错排查

6.1 lastrowid 返回 None

最常见原因:表没有 AUTO_INCREMENT 主键,或者你手动给自增列传了值。检查表结构:

SHOW CREATE TABLE users;

确认 id 列带 AUTO_INCREMENT。另外,如果 INSERT 因为唯一键冲突失败,lastrowid 也可能是 None 或旧值,务必先判断 execute 是否抛异常。

6.2 executemany 后只拿到一个 ID

这是驱动行为,不是 bug。需要全部 ID 就改逐行插入,或者改用 UUID 主键。别试图用 lastrowid 加行数推算,并发下必错。

6.3 多线程下 ID 串了

只要每个线程用独立连接,lastrowid 就是连接隔离的,不会串。串的原因通常是多个线程共用一个 connection 或 cursor。连接池场景下,确保从池里借出的连接在同一线程内用完即还。

6.4 PyMySQL 的差异

PyMySQL 同样支持 cursor.lastrowid,行为一致。但 PyMySQL 默认 autocommit=False,忘记 commit 会导致数据不落库,回查时找不到。另外 PyMySQL 连接参数用 charset='utf8mb4',别写成 utf-8。

6.5 时区与 DATETIME 对不上

registered_at 用 DEFAULT CURRENT_TIMESTAMP 时,取回的时间取决于 MySQL 服务器时区。如果 Python 侧显示差 8 小时,在连接参数里加 time_zone='+08:00',或在 MySQL 配置里统一时区。

6.6 连接超时导致插入中断

长事务或网络抖动会让连接断掉,此时 commit 抛异常,lastrowid 不可信。给连接加 connection_timeout,并在 except 里显式 rollback。重试逻辑要放在应用层,别在驱动层硬扛。

7. 把模型调用也接进同一套配置

当你的脚本需要在插入前用大模型生成 username 或 email 模板时,可以直接读同一份配置里的 TaoToken 段:

import json, urllib.request def call_model(prompt: str, cfg: dict) -> str: req = urllib.request.Request( f"{cfg['base_url']}/v1/messages", data=json.dumps({ "model": cfg["default_model"], "max_tokens": 256, "messages": [{"role": "user", "content": prompt}] }).encode(), headers={ "Content-Type": "application/json", "x-api-key": cfg["api_key"], "anthropic-version": "2023-06-01" }, method="POST" ) with urllib.request.urlopen(req, timeout=30) as resp: return json.loads(resp.read())["content"][0]["text"]

这样数据库凭据和模型凭据都在 settings.json 里,换环境只改一份文件。想先验证模型是否通,可以去模型对话页 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 手动发一条消息确认 Key 有效。如果是要长期跑编码任务或 Agent 流程,Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 会更合适。接入细节和参数说明在文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 里,Claude Code 相关配置参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite 。

8. 收尾:几个我实际用下来的习惯

第一,lastrowid 拿到后立刻赋值给局部变量,别在中间插任何其他 INSERT。第二,executemany 场景一律不依赖 lastrowid,要么逐行,要么 UUID。第三,校验动作别省,尤其是跨服务写库时,回查一次能挡掉大部分「以为成功其实回滚」的问题。第四,配置文件里的敏感字段用环境变量覆盖,settings.json 只留占位符。第五,连接用完即关,with 语句能省掉一堆 finally 样板代码。

把这些串起来,Python 与 MySQL 的自增 ID 获取链路就稳了。

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

srt-whiteboard-animation的7步工作流:从字幕文件到成片MP4的完整指南

srt-whiteboard-animation的7步工作流:从字幕文件到成片MP4的完整指南 【免费下载链接】srt-whiteboard-animation 将 SRT 字幕做成暖米黄纸张底的流式笔迹白板手绘动画 skill:mask 分区遮罩编排 stream 连续笔迹(ink→color)。 …

作者头像 李华
网站建设 2026/9/26 12:07:45

AI漫剧与AI电影后期渲染:智慧文旅沉浸式内容轻量化生产实战指南

1. 从一条政策信号说起:为什么"AI漫剧"突然成了文旅圈的热词前阵子跟几个做文旅数字化的老朋友吃饭,席间有人提到黑龙江那份关于智慧文旅的文件,重点圈了两个方向:一个是沉浸式体验新空间,另一个是AI漫剧制作…

作者头像 李华
网站建设 2026/9/26 12:07:24

3C连接器压装0.02mm公差控制全流程解析

做3C连接器压装的朋友,应该都有这种体会:0.02mm这个数字放在图纸上就是一行技术条件,落到产线上却是一道能让人翻来覆去折腾好久的坎。连接器、压装、公差这三个词绑在一起,就意味着你既要管得住来料尺寸,又要压得稳设…

作者头像 李华
网站建设 2026/9/26 12:06:23

Python实战项目怎么练?108个项目按能力阶梯拆解与源码学习指南

1. 为什么“收藏了108个项目”的人,最后往往一个都没跑通我见过太多人硬盘里躺着几十个G的“Python实战项目合集”,文件夹命名从“入门”到“进阶”再到“大厂真题”,结果打开率不到百分之五。问题不在项目本身,而在于项目清单和练…

作者头像 李华
网站建设 2026/9/26 12:05:36

设置EditText光标颜色:从 colorAccent 到 textCursorDrawable 的完整配置

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

作者头像 李华
网站建设 2026/9/26 12:05:22

STM32 HAL库DMA+IDLE中断实现SBUS解析实战

1. 为什么SBUS解析值得单独拿出来讲SBUS这个协议在航模和机器人圈子里太常见了,接收机、飞控、舵机控制器之间几乎都用它通信。但很多刚接触STM32的朋友第一次拿到SBUS信号时,往往会卡在几个地方:串口参数怎么配、数据怎么收才不丢帧、帧头帧…

作者头像 李华