EP08 · 讲义
Genesis2000 Python 脚本实战 · 第8集 数据库——业务库与配置库
本集学什么
这集讲数据。学完你能独立写数据库操作:查料号参数、写配置、留日志。 两套体系各讲透:远程业务库怎么封装,本地配置库怎么设计,最后看几个工程细节。
回顾:数据从哪来、到哪去
- 第 6 集:ERP 查询底层走 SqlClasses
- 第 7 集:界面配置存 db_manager
第 6 集的 ERP 查询,底层走的就是这集要讲的 SqlClasses;第 7 集的界面配置,就存在这集的 db_manager 里。 数据层是前面所有故事的幕后支撑。这集把它请到台前。
两套体系的定位
# 远程业务库 SQL Server / MySQL —— 料号·快板·计划
# 本地配置库 SQLite —— 菜单·主题·设置
第一套是 SqlClasses:连接远程的 SQL Server 和 MySQL,读写业务数据——料号库、快板库、计划库。 第二套是 db_manager:本地的 SQLite 文件,保存界面程序的配置——菜单、主题、用户设置。数据性质不同,技术选型不同,封装也分开。
通用封装:两个核心方法(完整源码)
def exec_query(self, sql): # 查询 → list[dict] / list[tuple]
...执行...
fetchall()
close() # 用完即关
def exec_non_query(self, sql): # 写入 → "ok" / "no"
...执行...
SqlClasses 的核心就两个方法:exec_query 查,exec_non_query 写。查询结果可以选字典列表或元组列表两种模式,构造子类时指定。 写入失败会弹错误框提示,返回 no。业务脚本里百分之九十九的数据库操作,这两个方法就够。
字典生成 SQL
_make_sql(表名, {字段: 值, ...}) → INSERT INTO 表 (字段...) VALUES (...)
→ None 自动转成 NULL
- 手工拼 SQL 的引号、逗号、空值错误,消灭在源头
还有个贴心的功能:传一个字典,自动生成插入语句——键是字段名,值是数据,None 自动转成数据库的 NULL。 手工拼 SQL 是出错重灾区:引号、逗号、空值。这个生成器把这类低级错误消灭在源头。
预置连接子类
- 快板库连接类
- ERP 库连接类
- 中心库连接类
- 计划库连接类
- 通用能力在父类,连接细节在子类
- 新增一个库 = 加一个几行的子类
每个业务库对应一个子类,连接参数在类里预置好。要用快板库,实例化对应子类就行,不用记服务器地址、账号、库名。 设计取向很明确:通用能力在父类,连接细节在子类。新增一个库,只需加一个几行的子类——典型的模板方法思想。
用完即关的取舍
- 每次调用新建连接
- 用完立即关闭
- 注释提醒「查询完毕后必须关闭连接」
- 牺牲一点握手开销,换来不用管理连接生命周期
- 工程上,够用就好
一个值得讲的取舍:每次数据库操作都新建连接、用完即关,没有连接池。代码里还有注释专门提醒必须关闭。 代价是每次连接的握手开销,好处是简单可靠——脚本场景的数据库操作频率不高,换来不用管理连接生命周期。工程上,够用就好。
MySQL 版本兼容
- 5.7 与 8.0 游标行为差异
- cursor 失败改用 DictCursor
- 兼容逻辑藏在封装内部,调用方完全无感
- 「先试再换」的写法很实用
MySQL 的兼容处理值得一看:不同版本返回游标的行为有差异,代码里先按一种方式取,失败再换另一种。 兼容逻辑藏在封装内部,调用方完全无感。对接外部系统时,这类「先试再换」的写法很实用。
Python2 残留的识别
raise (NameError, "message") # Python2 元组式异常
- 不会报错,只是静默失效
- 看到陌生语法,先怀疑是不是历史包袱
老代码里还能看到 Python2 时代的写法:元组形式的异常抛出。这种写法在 Python3 里已经不生效。 认得出这些残留很重要——它们不会报错,只是静默失效。读老代码时看到陌生语法,先怀疑是不是历史包袱。
db_manager:SQLite 配置库
- docstring 原话:替代 JSON 文件
- 提供事务保护、并发安全、内置版本
再看本地配置库 db_manager。模块开头就写着设计理由:替代 JSON 文件,提供事务保护、并发安全、内置版本。 过去界面配置散落在多个 JSON 文件里,读写出错难查;换成 SQLite,一个文件、事务保证、结构清晰。
表结构与变更留痕
- 界面设置
- 菜单配置
- 流程列表
- 管理员
- 主题模板
- 系统信息
- 变更日志
表结构七张:界面设置、菜单配置、流程列表、管理员、主题模板、系统信息,外加一张变更日志。 变更日志是亮点——每次配置改动自动记一笔。配置被谁改过、改成什么,出了问题可以回溯。
WAL 与事务(完整代码)
PRAGMA journal_mode=WAL # 读写并发安全
with conn: # 事务块:要么全成,要么全不
...写入 + 记日志
两个可靠性细节。第一,启用 WAL 模式:SQLite 的预写日志,让读写可以并发,多进程访问不冲突。 第二,写入包在事务块里:一条配置的写入和它的日志记录要么一起成功,要么一起回滚——不会出现「改了配置但没记录」的中间状态。
一次性迁移
- migrate_from_json 批量导入旧配置
- 主题 / 菜单 / 系统配置全覆盖
- _is_migrated 防重复执行
- 老版本升级新版本,数据平滑过渡
- 「一次性迁移」模式很值得学
从 JSON 换到 SQLite,老数据怎么办?代码里写了迁移函数:启动时把旧的 JSON 文件批量导入新库,主题、菜单、系统配置都覆盖。 迁移函数带防重复标记,只执行一次。老版本升级到新版本,数据平滑过渡——这种「一次性迁移」模式很值得学。
使用案例巡览
sql.exec_query("SELECT ... FROM 料号表") # 查业务库sql.exec_non_query("UPDATE ...") # 写业务库dbm.set_ui_settings(key, value) # 写本地配置
- 摘自包内 docstring「使用例子」原文
- 下一集:ApiClasses 与辅助模块
最后看真实用法。查业务库、写业务库,各一行;写本地配置,也是一行——前面六集见过的所有数据操作,都汇聚在这几行里。 下一集看外围模块:自动化任务的触角——企微推送、涨缩系数接口、文件传输、邮件通知。
小结与预告
这一集我们看到:数据层分了两套——业务数据走远程库,配置数据走本地库,各自有各自的封装与取舍。 下一集看外围部队:企业微信推送、涨缩系数接口、文件传输、邮件通知——自动化任务的触角是怎么伸出去的。
零壹AI工作室出品 · 《用 Python 驱动 Genesis2000》免费公开课 · www.binwindai.com