资讯动态

Python 添加记录到有自增长ID的表,如何获取新产生的ID:TaoToken 统一 Key 通道下的 sqlite 与 oracle 实测

发布时间:2026/10/4 9:48:41 来源:尧图企业网站定制
1. Python 插入自增表后取回新 ID 的典型场景与坑位在 Python 里往带自增长 ID 的表插数据然后拿到数据库刚生成的那个 ID是几乎每个后端项目都会遇到的动作。比如你写一个方案管理模块用户点「新建方案」你插入一条记录紧接着要把这个新 ID 返回给前端或者拿它去写关联表、写日志、拼跳转链接。听起来简单但 sqlite 和 oracle 这两套数据库给出的答案完全不一样很多人第一次写 oracle 的时候会直接懵掉。核心检索词先摆出来Python 添加记录到有自增长ID的表如何获取新产生的ID。这个问题在 sqlite 和 oracle 上的解法差异主要集中在三个东西上——cursor.lastrowid、RETURNING INTO、sequence.currval。你把这三个搞明白基本就不会再踩坑了。先说 sqlite。sqlite 是 Python 标准库sqlite3直接内建的不需要额外装驱动。它的自增列一般写成INTEGER PRIMARY KEY AUTOINCREMENT插入之后cursor.lastrowid直接就是新生成的 ID一行代码搞定非常省心。这也是为什么很多人先在 sqlite 上把逻辑跑通再迁到 oracle 时以为照抄就行结果发现lastrowid返回的根本不是 ID 列的值。再说 oracle。oracle 里自增通常靠 sequence trigger或者 12c 之后的GENERATED BY DEFAULT AS IDENTITY。用cx_Oracle现在官方推荐python-oracledb插入后cursor.lastrowid拿到的是 oracle 内部的ROWID它是一个物理地址标识不是你的业务 ID 列。你得拿这个ROWID再select id from 表 where rowid:1才能取回真正的 ID。另一种更规范的做法是用RETURNING id INTO :out绑定变量一次往返直接拿到 ID效率更高。我试过在一个混合环境里同时维护 sqlite 本地库和 oracle 生产库同一套业务代码要兼容两边取 ID 这块如果不抽象好代码会变得很脏。下面我把建表、插入、取 ID、验证的完整流程拆开写每一步都能直接复制运行。你跟着走一遍就能确认取回的 ID 和表里实际记录是一致的而不是「看起来对」。这一篇适合谁正在用 Python 操作 sqlite 或 oracle、需要拿到自增主键的开发者被lastrowid在 oracle 上返回怪值坑过的人以及想把取 ID 逻辑统一封装、避免两套代码的人。接下来先讲 TaoToken 统一 Key 通道的前置准备再进入可复制的配置和脚本。2. TaoToken 统一 Key 通道前置准备一个 Key 打通 sqlite 与 oracle 调试在真正写取 ID 脚本之前我想先解决一个很现实的问题调试这类数据库交互代码时你经常需要让 AI 帮你解释报错、生成兼容两套数据库的封装、或者对比RETURNING INTO和currval的写法。如果每次都要在多个模型、多个工具之间切换Key 管理会非常乱。TaoToken 的统一 Key 通道就是干这个的——一个 Key 走通模型对话、编码辅助、API 调用省掉到处配 Key 的麻烦。官网入口在这里https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。你可以先注册拿到统一 Key后面无论是让模型帮你审 sqlite/oracle 的取 ID 代码还是直接调 API 做批量验证都用同一个 Key。为什么调试数据库取 ID 这件事特别需要 AI 辅助因为 sqlite 和 oracle 的差异不是靠记忆能稳的。比如lastrowid在 sqlite 上是 ID在 oracle 上是 ROWIDRETURNING INTO在 oracle 里要配合绑定变量sequence.currval必须在同会话里先nextval过才能用。这些细节你让模型帮你逐条核对比翻文档快得多。TaoToken 的 API 地址是 https://taotoken.net/api 注意这个地址不带 UTM 参数配置的时候直接用。模型对话入口在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 你可以在这里让模型帮你生成下面要用的建表和插入脚本。API Keys 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。前置准备分三步。第一步拿到统一 Key记下来后面配置里会用到。第二步确认你的 Python 环境sqlite 用标准库sqlite3即可oracle 需要装oracledbpip install oracledb它是cx_Oracle的继任者API 基本兼容。第三步如果你打算用 AI 辅助生成兼容代码把 TaoToken 的 Base URL 和 Key 配到你的编码工具里这样模型能直接读你的代码上下文。这里要强调一点TaoToken 是统一 Key 通道不是让你绕过任何东西它只是把多个模型的调用收敛到一个 Key 上方便管理和计费。你调试数据库代码时用它来问问题、生成脚本、解释报错都是正常开发流程的一部分。配好之后你就可以让模型帮你做一件很有价值的事把 sqlite 和 oracle 两套取 ID 逻辑抽象成一个函数输入是连接和 SQL输出是新 ID。这个抽象如果自己写容易漏掉边界情况让模型先给一版你再改效率高很多。下一节进入可复制的配置和脚本包括 TaoToken 的配置片段和两套数据库的建表插入代码。3. 可复制配置TaoToken settings 片段与 sqlite/oracle 建表插入脚本这一节全是能直接复制的东西。先给 TaoToken 的配置片段再给 sqlite 和 oracle 的建表、插入、取 ID 脚本。配置片段我用 JSON 和 TOML 两种格式各给一份你按自己用的工具选。先看 TaoToken 的统一配置。如果你用的是支持 OpenAI 兼容接口的工具配置大概长这样{ base_url: https://taotoken.net/api, api_key: 你的统一Key, model: claude-sonnet-4-20250514, timeout: 60 }如果你用的是 TOML 风格的配置文件比如某些 CLI 工具写成这样[provider.taotoken] base_url https://taotoken.net/api api_key 你的统一Key model claude-sonnet-4-20250514注意 Base URL 是https://taotoken.net/api不要多加路径。Key 从 API Keys 页面拿。Model ID 按你实际要用的填上面只是示例。这三件套——Base URL、Key、Model ID——是任何接入场景都必须对齐的缺一个都会报错。接下来是 sqlite 部分。建表语句CREATE TABLE IF NOT EXISTS JYFA ( id INTEGER PRIMARY KEY AUTOINCREMENT, fieldlabel TEXT NOT NULL, FIELDTYPE INTEGER DEFAULT 0, pid INTEGER DEFAULT 0, dsporder INTEGER DEFAULT 0 );插入并取回新 ID 的 Python 代码import sqlite3 def add_fangan_sqlite(conn, label): c conn.cursor() c.execute( INSERT INTO JYFA (fieldlabel, FIELDTYPE, pid, dsporder) VALUES (?, ?, ?, ?), (label, 0, 0, 0) ) new_id c.lastrowid conn.commit() return new_id conn sqlite3.connect(demo.db) conn.execute(CREATE TABLE IF NOT EXISTS JYFA ( id INTEGER PRIMARY KEY AUTOINCREMENT, fieldlabel TEXT NOT NULL, FIELDTYPE INTEGER DEFAULT 0, pid INTEGER DEFAULT 0, dsporder INTEGER DEFAULT 0 )) conn.commit() nid add_fangan_sqlite(conn, 测试方案A) print(sqlite 新 ID:, nid)sqlite 这里lastrowid就是 ID 列的值直接返回即可。注意commit要在取lastrowid之后、返回之前顺序别乱。再看 oracle。oracle 12c 之后可以用 IDENTITY 列建表CREATE TABLE JYFA ( id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, fieldlabel VARCHAR2(200) NOT NULL, FIELDTYPE NUMBER DEFAULT 0, pid NUMBER DEFAULT 0, dsporder NUMBER DEFAULT 0 );如果你用的是老版本 oracle靠 sequence trigger那就先建 sequenceCREATE SEQUENCE SEQ_JYFA START WITH 1 INCREMENT BY 1;然后用RETURNING INTO取 ID这是最推荐的方式import oracledb def add_fangan_oracle_returning(conn, label): c conn.cursor() new_id c.var(oracledb.NUMBER) c.execute( INSERT INTO JYFA (fieldlabel, FIELDTYPE, pid, dsporder) VALUES (:1, :2, :3, :4) RETURNING id INTO :5, (label, 0, 0, 0, new_id) ) conn.commit() return int(new_id.getvalue()[0]) conn oracledb.connect(user你的用户, password你的密码, dsn你的DSN) nid add_fangan_oracle_returning(conn, 测试方案B) print(oracle 新 ID:, nid)RETURNING id INTO :5里的:5是一个输出绑定变量c.var(oracledb.NUMBER)声明它执行后new_id.getvalue()[0]就是新 ID。这种方式一次往返就拿到比先插再查快。如果你只能用lastrowid的老写法oracle 上要这样绕def add_fangan_oracle_rowid(conn, label): c conn.cursor() c.execute( INSERT INTO JYFA (fieldlabel, FIELDTYPE, pid, dsporder) VALUES (:1, :2, :3, :4), (label, 0, 0, 0) ) rowid_val c.lastrowid c2 conn.cursor() c2.execute(SELECT id FROM JYFA WHERE rowid :1, (rowid_val,)) new_id c2.fetchone()[0] conn.commit() return new_id这里lastrowid拿到的是 ROWID不是 ID必须再查一次。这就是 excerpt 里提到的那个坑。两种方式都给你按 oracle 版本和习惯选。sequence.currval 的用法也要提一下。如果你在插入前手动取了SEQ_JYFA.nextval那插入后可以用SEQ_JYFA.currval拿当前会话最后生成的值c.execute(SELECT SEQ_JYFA.nextval FROM dual) seq_val c.fetchone()[0] c.execute(INSERT INTO JYFA (id, fieldlabel) VALUES (:1, :2), (seq_val, label)) conn.commit() return seq_val但currval必须在同会话里先nextval过否则报错。跨会话用currval是拿不到别人生成的值的这点要记住。配置和脚本都齐了下一节做逐步验证确认取回的 ID 和表里实际记录一致。4. 逐步验证请求确认取回的 ID 与表中实际记录一致光看代码返回一个数字不够你得验证这个数字确实是表里那条新记录的 ID。这一节给你一套逐步验证动作sqlite 和 oracle 各走一遍。sqlite 验证。先插一条拿到返回的 ID再按这个 ID 查一次看字段是否对得上import sqlite3 conn sqlite3.connect(demo.db) c conn.cursor() c.execute(INSERT INTO JYFA (fieldlabel, FIELDTYPE, pid, dsporder) VALUES (?, ?, ?, ?), (验证方案, 1, 2, 3)) new_id c.lastrowid conn.commit() c.execute(SELECT id, fieldlabel, FIELDTYPE, pid, dsporder FROM JYFA WHERE id ?, (new_id,)) row c.fetchone() print(返回 ID:, new_id) print(表内记录:, row) assert row is not None and row[0] new_id and row[1] 验证方案 print(sqlite 验证通过)跑完你会看到返回 ID 和表内记录的 id 一致fieldlabel 也是你插的值。如果row是 None说明 ID 取错了或者事务没提交。oracle 验证用RETURNING INTO版本import oracledb conn oracledb.connect(user你的用户, password你的密码, dsn你的DSN) c conn.cursor() new_id c.var(oracledb.NUMBER) c.execute( INSERT INTO JYFA (fieldlabel, FIELDTYPE, pid, dsporder) VALUES (:1, :2, :3, :4) RETURNING id INTO :5, (验证方案O, 1, 2, 3, new_id) ) conn.commit() returned_id int(new_id.getvalue()[0]) c2 conn.cursor() c2.execute(SELECT id, fieldlabel FROM JYFA WHERE id :1, (returned_id,)) row c2.fetchone() print(返回 ID:, returned_id) print(表内记录:, row) assert row is not None and row[0] returned_id and row[1] 验证方案O print(oracle 验证通过)如果你用的是lastrowid ROWID 版本验证逻辑一样只是取 ID 的方式不同。重点是对比「返回的 ID」和「按 ID 查出来的记录」是否匹配。再给一个批量验证的思路确认连续插入时 ID 是递增且唯一的ids [] for i in range(5): c.execute(INSERT INTO JYFA (fieldlabel) VALUES (?), (f批量{i},)) ids.append(c.lastrowid) conn.commit() print(批量返回 ID:, ids) c.execute(SELECT id FROM JYFA WHERE fieldlabel LIKE 批量% ORDER BY id) db_ids [r[0] for r in c.fetchall()] print(表内 ID:, db_ids) assert ids db_ids print(批量验证通过)这段能帮你确认lastrowid在连续插入时不会串号。sqlite 上一般没问题oracle 上如果你用 sequence要确认 sequence 的 cache 设置不会导致跳号——跳号是正常的但取回的 ID 必须和表里一致。验证过程中如果想让 AI 帮你解释某一步的输出可以把结果贴到模型对话里问。TaoToken 的统一 Key 在这里就派上用场了同一个 Key 既能问模型又能调 API不用来回换。验证通过之后说明你的取 ID 逻辑是对的。下一节专门讲常见报错和排查这些错我在实际项目里都遇到过。5. 本篇常见错排查401、local proxy failed、reading choices 与 OAuth 报错这一节按真实报错来。你在配 TaoToken 或者调数据库取 ID 时可能撞上下面这些。401 Unauthorized。这个最常见基本是 Key 没配对。检查三件事Key 是不是从 API Keys 页面复制的完整字符串有没有多余空格Base URL 是不是https://taotoken.net/api有没有多写或少写路径请求头里Authorization: Bearer 你的Key格式对不对。如果三件套Base URL、Key、Model ID里任何一个不对都可能报 401 或类似的鉴权错。特别是 Model ID写错了有时不报 401 而是报模型不存在别混淆。local proxy failed。这个报错通常出现在你本地配了某种转发或代理设置但目标地址不可达。排查方向确认你的 Base URL 直接指向https://taotoken.net/api不要经过额外的本地转发层检查环境变量里有没有残留的代理配置干扰请求确认网络能正常访问该地址。如果你在容器里跑注意容器网络和宿主机的差异。这个错和数据库本身无关是请求链路的问题。reading choices 相关报错。这类错一般出现在解析模型返回时比如返回结构里没有choices字段或者choices为空。原因可能是请求体格式不对比如messages写成了别的字段名Model ID 不被支持或者返回的是错误结构而你按成功结构解析了。排查时先把原始返回打印出来看别直接取response[choices][0]。正确做法是先判断有没有error字段再取choices。OAuth 相关报错。如果你用的工具走 OAuth 流程接入报错通常是 token 过期、回调地址不匹配、或者 scope 不对。排查重新走一遍授权流程确认回调地址和配置里一致确认申请的权限范围覆盖你要用的能力。OAuth 和 API Key 是两种不同的鉴权方式别混用——用 Key 的场景就老老实实配 Key。除了接入层报错数据库取 ID 本身也有几个高频坑。sqlite 上如果你忘了commit就取lastrowid值可能对但记录没落库后续查询查不到。oracle 上lastrowid返回 ROWID 而不是 ID这是最容易踩的记住要再查一次或者用RETURNING INTO。sequence.currval跨会话拿不到值必须在同会话先nextval。RETURNING INTO的绑定变量类型要匹配NUMBER 列就用 NUMBER 类型的 var类型不对会报绑定错。还有一个隐蔽的坑oracle 的 IDENTITY 列和 sequence 混用时如果你手动插了 id 值IDENTITY 的计数器不会自动跳过后续可能主键冲突。要么全用 IDENTITY要么全用 sequence别混。排查顺序建议先确认接入层三件套对不对再看数据库连接是否正常最后看取 ID 的 SQL 和绑定变量。把原始报错完整贴给模型让它帮你定位比你自己猜快。TaoToken 的接入文档里有各场景的配置示例对着核一遍能省不少时间。6. 把取 ID 逻辑封装成可复用函数并接入 TaoToken 通道最后落到实操把 sqlite 和 oracle 的取 ID 逻辑封装成一个统一接口业务代码不用关心底层是哪个库。这样你迁移或者混用时改动只在一处。def insert_and_get_id(conn, db_type, table, columns, values): c conn.cursor() placeholders , .join([f:{i1} for i in range(len(values))]) if db_type oracle \ else , .join([?] * len(values)) col_str , .join(columns) sql fINSERT INTO {table} ({col_str}) VALUES ({placeholders}) if db_type sqlite: c.execute(sql, values) new_id c.lastrowid conn.commit() return new_id elif db_type oracle: out_id c.var(oracledb.NUMBER) c.execute(sql RETURNING id INTO :out, (*values, out_id)) conn.commit() return int(out_id.getvalue()[0]) else: raise ValueError(不支持的 db_type)调用时nid insert_and_get_id(conn, sqlite, JYFA, [fieldlabel, FIELDTYPE], [封装测试, 0]) print(新 ID:, nid)这个封装把差异吃掉了业务层只传db_type。注意 oracle 的RETURNING id INTO :out要求表的主键列名是id如果你的列名不同把id换成实际列名。封装好之后你可以让 TaoToken 通道里的模型帮你做代码审查比如问它「这个封装在 oracle 上用 IDENTITY 列时有没有问题」「sqlite 的 lastrowid 在并发插入时是否安全」。把代码贴进模型对话让它逐行看。模型对话入口在 https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 用统一 Key 直接问。如果你要长期做这类数据库兼容和 Agent 编码可以考虑 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 适合需要持续调用模型辅助开发的场景。API Keys 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后给你一个实用技巧在封装函数里加一行日志把db_type、表名、返回的 ID 打出来出问题时一眼能看出是哪个库哪张表取的 ID 不对。这个日志在混合环境里救过我很多次。取 ID 这件事sqlite 靠lastrowidoracle 靠RETURNING INTO或 ROWID 二次查询currval只在同会话有效——记住这三条基本就不会再被坑了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑