1. 从一次本地数据翻车说起:sqlite 增删改查到底难在哪
刚接触数据库那会儿,我总觉得 sqlite 是个"玩具"——一个文件、零配置、不用装服务,随手import sqlite3就能跑。直到有次写了个小工具,把用户填的表单存进data.db,结果第二天打开发现数据全没了,才意识到问题不在 sqlite 本身,而在我对 cursor 游标、事务提交、占位符传参这几件事的理解全是模糊的。
sqlite 是一款轻量级嵌入式数据库,整个数据库就是磁盘上的一个文件,源码约三万行 C 代码,占用资源极低,处理速度在小型数据场景下甚至比 MySQL、PostgreSQL 更快。它适合谁?适合刚学数据库的开发者、写本地小工具的人、做嵌入式或桌面应用的人,以及想在不搭服务的前提下练手 SQL 的人。你能用它做什么?建表、插入、查询、更新、删除,也就是常说的增删改查(CRUD),再加上 cursor 游标来逐条或批量取结果。
但小白最容易踩的坑集中在三处:第一,execute执行完不commit,程序一关数据就回滚;第二,占位符?传参时把参数写成了字符串拼接,既报错又有注入风险;第三,fetchone、fetchmany、fetchall混用,不知道游标位置是"接着上次往下走"的。这篇笔记就围绕 sqlite 增删改查全流程和 cursor 方法实操展开,每一步都给可直接复制的 SQL 与 Python 代码,最后再讲怎么把 AI 工具的 Base URL 统一改到 TaoToken,用一个 Key 管理所有模型调用,省得每个工具配一遍密钥。
我试过把建表、插入、查询、更新、删除拆成独立脚本跑一遍,再对照执行结果看游标行为,理解速度比只看文档快得多。下面按这个顺序来。
2. 前置准备:TaoToken 统一 Key 与 sqlite 环境搭好
在写增删改查之前,先把两件事准备好:本地 sqlite 环境,以及 AI 工具的 Key 统一管理。前者是 Python 自带的,后者是为了让你在写代码时能顺手让 AI 帮你补 SQL、查报错,而不用在多个平台之间来回切换密钥。
sqlite 环境几乎零成本。Python 3 内置sqlite3模块,不需要pip install任何东西。你只要确认 Python 版本:
python --version # 期望输出类似 Python 3.10.x 或更高然后验证 sqlite3 模块可用:
python -c "import sqlite3; print(sqlite3.sqlite_version)" # 期望输出类似 3.39.5如果这两条都正常,环境就齐了。数据库文件会在你第一次connect时自动创建,不用手动建库。
接下来是 TaoToken 的前置配置。TaoToken 是一个统一 API 入口,官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。它的作用是让你用同一个 Key 去调用不同模型,写代码时遇到 SQL 报错、cursor 行为不理解,可以直接在对话里问,不用每个工具单独配密钥。
你需要先拿到 Key。进入控制台创建 API Key,地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor 。创建后复制那串以sk-开头的密钥,妥善保存,页面关闭后通常不再完整显示。
拿到 Key 后,把它配到你的 AI 编码工具里。以常见的 OpenAI 兼容配置为例,Base URL 填https://taotoken.net/api,API Key 填你刚复制的那串,Model ID 按你实际要用的模型填。如果你用的是 Claude Code 这类工具,配置项名称可能不同,但三件套不变:Base URL、Key、Model ID。这三样缺一不可,尤其是 Model ID,填错会直接报模型不存在。
这里要提醒一句:TaoToken 是统一 API 入口,不是让你替代编辑器或数据库工具,它解决的是"多个 AI 工具密钥分散"的问题。sqlite 的增删改查还是在你本地 Python 里跑,两者互不干扰。
配置完成后,你可以先在模型对话页面发一条测试消息,确认 Key 有效。模型对话入口是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor 。如果返回正常,说明前置准备完成,可以进入代码环节了。
3. 可复制配置:建表、增删改查与 cursor 方法全代码
这一节是核心,所有代码都可以直接复制运行。我按"建表 → 插入 → 查询 → 更新 → 删除"的顺序来,每一步都说明游标在做什么。
先建一个统一的脚本骨架。数据库文件叫demo.db,表叫user,字段是id(主键)和name:
import sqlite3 # 连接数据库,文件不存在会自动创建 conn = sqlite3.connect("demo.db") cur = conn.cursor() # 建表,IF NOT EXISTS 避免重复建表报错 cur.execute(""" CREATE TABLE IF NOT EXISTS user ( id INTEGER PRIMARY KEY, name TEXT NOT NULL ) """) conn.commit() cur.close() conn.close() print("建表完成")运行后你会看到建表完成,同目录下多了一个demo.db文件。这里id INTEGER PRIMARY KEY表示主键,插入重复 id 会报错,这点后面排错会用到。
插入数据分单条和多条。单条用execute,多条用executemany,占位符统一用?,参数用元组或列表传,不要用字符串拼接:
import sqlite3 conn = sqlite3.connect("demo.db") cur = conn.cursor() sql = "INSERT INTO user (id, name) VALUES (?, ?)" # 插入一条 cur.execute(sql, (0, "lily")) # 插入多条,用列表保存 data = [(1, "li"), (2, "davy"), (3, "july")] cur.executemany(sql, data) cur.close() conn.commit() # 关键:不 commit 数据不会真正写入 conn.close() print("插入完成")注意conn.commit()的位置在cur.close()之后、conn.close()之前。查询不需要 commit,只有改变表内容(增、改、删)才需要。
查询是 cursor 方法体现最明显的地方。fetchone取一条,fetchmany(n)取 n 条,fetchall取剩余全部,而且游标位置是连续的——下一次取从上次结束的地方开始:
import sqlite3 conn = sqlite3.connect("demo.db") cur = conn.cursor() sql = "SELECT * FROM user WHERE id >= 0" cur.execute(sql) result1 = cur.fetchone() # 取第 1 条 result2 = cur.fetchone() # 取第 2 条 result3 = cur.fetchmany(3) # 从第 3 条开始取 3 条 result4 = cur.fetchall() # 取剩余全部 print("查找一条", result1) print("查找一条", result2) print("查找3条", result3) print("查找所有", result4) cur.close() conn.close()按前面插入的数据,输出应该是:
查找一条 (0, 'lily') 查找一条 (1, 'li') 查找3条 [(2, 'davy'), (3, 'july')] 查找所有 []最后fetchall返回空列表,因为四条数据已经被前面取完了。这就是游标"接着上次走"的直观体现,很多人第一次看到[]会以为查询失败,其实是游标到底了。
更新数据用UPDATE ... SET ... WHERE ...,同样支持单条和多条:
import sqlite3 conn = sqlite3.connect("demo.db") cur = conn.cursor() sql = "UPDATE user SET name = ? WHERE id = ?" # 单条更新 cur.execute(sql, ("lily_update", 0)) # 多条更新 data = [("update1", 1), ("update2", 2)] cur.executemany(sql, data) cur.close() conn.commit() conn.close() print("更新完成")删除用DELETE FROM ... WHERE ...,注意WHERE条件别写错,否则会删全表:
import sqlite3 conn = sqlite3.connect("demo.db") cur = conn.cursor() sql = "DELETE FROM user WHERE id >= ?" cur.execute(sql, (1,)) # 单元素元组要带逗号 cur.execute("SELECT * FROM user") result = cur.fetchall() print("删除后剩余", result) cur.close() conn.commit() conn.close()执行后剩余[(0, 'lily_update')],因为 id 大于等于 1 的都被删了。这里(1,)的单元素元组逗号不能省,写成(1)会被当成整数,导致参数数量不匹配报错。
如果你用 AI 工具辅助写这些 SQL,把 Base URL 配到 TaoToken 后,可以直接在对话里贴报错让它分析。比如 cursor 取数顺序不对、commit 漏了,都能快速定位。需要长期做编码和 Agent 任务的,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor 。
4. 验证请求:跑一遍看执行结果与成功标志
代码写完不算完,得跑一遍确认结果符合预期。这一节把完整流程串起来,给你一个可对照的验证清单。
第一步,确认数据库文件生成。运行建表脚本后,用命令行查看:
ls -lh demo.db # 期望看到 demo.db 文件,大小几 KB 到几十 KB第二步,插入后验证数据条数。可以用 Python 快速查:
import sqlite3 conn = sqlite3.connect("demo.db") cur = conn.cursor() cur.execute("SELECT COUNT(*) FROM user") print("当前记录数", cur.fetchone()) cur.close() conn.close()插入四条后应输出当前记录数 (4,)。
第三步,验证 cursor 取数顺序。把第 3 节的查询脚本原样跑一遍,对照输出:
查找一条 (0, 'lily') 查找一条 (1, 'li') 查找3条 [(2, 'davy'), (3, 'july')] 查找所有 []如果fetchmany(3)返回的不是从第 3 条开始,而是又从第 1 条开始,说明你在中间重新execute了查询,游标被重置了。这是常见误解:每次execute都会重新定位游标到结果集开头。
第四步,验证更新生效。更新后查询 id 为 0 的记录:
cur.execute("SELECT * FROM user WHERE id = 0") print(cur.fetchone()) # 期望 (0, 'lily_update')第五步,验证删除范围。删除 id >= 1 后,全表查询应只剩 id 为 0 的记录。如果还剩其他记录,检查WHERE条件是否写成了id > 1或漏了参数。
第六步,验证事务提交。这是最容易翻车的一步。故意写一个不 commit 的脚本:
import sqlite3 conn = sqlite3.connect("demo.db") cur = conn.cursor() cur.execute("INSERT INTO user (id, name) VALUES (?, ?)", (99, "no_commit")) cur.close() conn.close() # 没有 commit然后重新连接查询 id 为 99 的记录,你会发现查不到。这就是事务未提交导致数据回滚。把conn.commit()补上再跑,就能查到。这个验证能帮你彻底记住 commit 的作用。
如果你在验证过程中让 AI 帮你分析输出,记得 Base URL 用https://taotoken.net/api,Key 用控制台创建的那串,Model ID 填对。三件套齐了,AI 才能正确读到你的报错上下文。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor ,遇到配置问题可以对照查。
5. 本篇常见错排查:401、占位符、游标到底、commit 漏写
跑 sqlite 增删改查时,报错大多集中在几类。这一节按真实报错对照排查,顺便把 AI 工具配置的坑一起讲了。
第一类,sqlite3.OperationalError: no such table: user。原因是你还没建表就插入或查询。解决:先跑建表脚本,确认demo.db里表存在。可以用SELECT name FROM sqlite_master WHERE type='table'查看所有表。
第二类,sqlite3.IntegrityError: UNIQUE constraint failed: user.id。主键重复。插入时 id 具有唯一性,不能插相同 id。解决:换一个没用过的 id,或者把主键改成INTEGER PRIMARY KEY AUTOINCREMENT让数据库自增。
第三类,sqlite3.ProgrammingError: Incorrect number of bindings supplied。占位符数量和参数数量不匹配。常见于execute(sql, (1))这种写法,单元素元组漏了逗号。解决:写成(1,)。另外executemany的第二个参数必须是列表或元组的序列,不能是单个元组。
第四类,查询返回空列表[]。不一定是没数据,很可能是游标已经到底。比如你先fetchall再fetchone,第二次必然为空。解决:需要重新取数就重新execute一次查询,游标会重置到开头。
第五类,数据插入后查不到。九成是漏了conn.commit()。sqlite 默认开启事务,增删改不提交不会落盘。解决:在cur.close()后、conn.close()前加conn.commit()。查询不需要 commit。
第六类,AI 工具报401 Unauthorized。这是 Key 无效或没带上。检查 Base URL 是否为https://taotoken.net/api,Key 是否完整复制(以sk-开头),有没有多余空格。如果用的是 Claude Code 类工具,确认配置项名称对应正确,三件套 Base URL、Key、Model ID 都要填。
第七类,报local proxy failed或连接超时。先确认网络能正常访问 API 端点,再检查 Base URL 有没有多写或少写路径。TaoToken 的 API 端点是https://taotoken.net/api,不要自己拼/v1之类的后缀,除非文档明确要求。
第八类,报reading choices相关错误。通常是返回结构和你工具预期的格式不一致,多半是 Model ID 填错,或者用了不支持的模型名。解决:核对 Model ID 拼写,确认该模型在你的套餐内可用。
第九类,OAuth 相关报错。如果你用的是需要 OAuth 授权的工具,确认授权流程走完,Token 没过期。这类问题在接入文档里有说明,对照检查即可。
第十类,cursor对象关闭后继续使用报ProgrammingError: Cannot operate on a closed cursor。解决:cur.close()之后不要再调execute或fetch,需要继续操作就重新conn.cursor()。
把这几类对照一遍,基本能覆盖新手 90% 的报错。遇到没列出的,把完整报错贴到 AI 对话里,让它结合你的代码分析,比盲猜快得多。
6. 把 Key 统一到 TaoToken:后续编码与 Agent 的接入方式
sqlite 的增删改查跑通后,你可能会想把它接进更大的项目,比如写个带 AI 辅助的数据管理工具,或者让 Agent 自动生成 SQL 并执行。这时候密钥管理就成了问题——不同工具、不同模型各配一套 Key,改起来很烦。TaoToken 的价值就在这里:一个 Key 管所有模型调用。
具体接入方式分两种场景。第一种是模型对话和临时问答,直接用模型对话页面,Base URL 和 Key 配好后就能问 SQL 相关问题。入口是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor 。
第二种是长期编码和 Agent 任务。如果你在写一个需要反复调用模型的脚本,或者用 Claude Code 这类工具做开发,建议用 Coding Plan,配置一次长期可用。地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor 。配置时记住三件套:Base URL 填https://taotoken.net/api,Key 填控制台创建的密钥,Model ID 按实际模型填。这三样在 Claude Code、Cline MCP、Codex 的auth.json里都是必需的,缺一个就连不上。
如果你用的是 Codex,auth.json里通常要写 Base URL、Key、Model ID 三项。Cline MCP 的配置类似,在 MCP 服务配置里填这三样。Claude Code 的配置项名称可能不同,但本质不变。配置完先发一条测试请求,确认返回正常再进正式开发。
需要新建或管理 Key 时,去 API Keys 页面:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor 。建议给不同项目建不同的 Key,方便追踪用量,也方便某个 Key 泄露时单独吊销。
最后回到 sqlite 本身。增删改查和 cursor 方法是数据库入门的基本功,练熟之后你会发现,不管是换 MySQL 还是 PostgreSQL,核心思路都一样:连接、游标、执行 SQL、提交事务、关闭。区别只在驱动和占位符写法。把 sqlite 这套跑通,再迁移到其他数据库,成本很低。
如果你在配置 TaoToken 或跑 sqlite 代码时遇到问题,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=sqlite_crud_cursor ,里面有各工具的详细配置步骤。先把 Base URL、Key、Model ID 三件套核对一遍,大部分连接问题都能解决。