第十五章 数据库操作
篇别:第三篇 数据库与数据管理
本章学习目标
- 能在确需时 安全地 使用原生 SQL(参数化),并理解 绕过 ORM 对权限与缓存的影响。
- 了解
odoo.tools.SQL(或当前版本等价 API)组合 SQL 的方式,避免注入。 - 能规划 模块迁移脚本 与 大表变更 的风险控制。
- 能执行 备份/恢复(含 filestore)并理解 RPO/RTO 基本概念。
导读:ORM 优先,SQL 慎用
Odoo 日常开发应 优先 ORM:自动处理 权限、多公司、翻译字段、审计。原生 SQL 适用于:重型报表、批量维护、与外部 DBA 协作的优化。一旦手写 SQL,你必须 自行保证 访问控制与安全。
15.1 SQL 查询
15.1.1 知识要点
self.env.cr(或self._cr已废弃):游标与当前事务绑定。execute(query, params):务必使用%s占位符 + 元组参数,禁止% name类字符串拼接。- 只读查询:长报表可考虑
READ ONLY游标或副本库(PG 特性,视配置而定)。 - 返回:
cr.fetchall()/dictfetchall()(若可用)等。
15.1.2 案例
案例 A:安全查询
self.env.cr.execute(
"SELECT id, name FROM library_book WHERE isbn = %s",
(isbn,),
)
rows = self.env.cr.fetchall()
案例 B:危险写法(禁止)
# 禁止
self.env.cr.execute("SELECT id FROM library_book WHERE name = '%s'" % name)
案例 C:ORM 与 SQL 混用
先 SQL 取 id 列表,再 self.env['library.book'].browse(ids) 做后续 ORM 操作(注意 browse 会校验权限,若用 sudo 则须自律)。
15.1.3 截图占位

15.1.4 本节练习
- 改错:解释
"WHERE name = '%s'" % name在name含'时会发生什么。 - 实操:对
library_book上一句按isbn查询的 EXPLAIN,判断是否走索引。 - 简答:手写 SQL 时 记录规则 是否自动生效?
参考答案提示:1. 注入或语法错误。3. 不生效,须自行叠加条件或改用 ORM。
15.2 SQL Wrapper(补充)
15.2.1 知识要点
Odoo 提供 SQL 等工具类(包路径与 API 以 19.0 文档与源码 为准),用于:
- 拼接 WHERE 子句片段仍保持 绑定参数;
- 标识符引用
Identifier防止误拼表名; - 在 Domain 转 SQL 等内部逻辑中与 ORM 一致化。
15.2.2 案例(概念性,具体 import 以版本为准)
from odoo.tools import SQL
# 伪代码示意:实际构造方式见官方文档
# sql = SQL("SELECT id FROM library_book WHERE isbn = %s", isbn)
# self.env.cr.execute(sql)
15.2.3 截图占位

15.2.4 本节练习
- 实操:找一段项目中 字符串拼接 的 SQL,改写为 参数化(或
SQL对象)。 - 简答:
SQL对象相对裸字符串的 团队维护 优势?
15.3 数据库迁移
15.3.1 知识要点
- Odoo 模块升级:
-u module触发 模型同步、视图更新、XML/CSV 重载(受 noupdate 影响)。 - 版本迁移脚本:
migrations/<version>/下 pre/post 脚本(命名与执行机制以 upgrade 工具 / Odoo 版本 为准)。 - 大表 DDL:
ADD COLUMN/CREATE INDEX CONCURRENTLY(PG)等需 锁与时长 评估;优先在 低峰 或 维护窗 执行。 - 流程:备份 → 副本验证 → 生产执行 → 验证回滚路径。
15.3.2 案例
pre-migrate:在 ORM 改表结构 前 做数据清洗(如拆分列、填默认值)。
post-migrate:结构已就绪后 批量 UPDATE、重建统计信息。
15.3.3 截图占位

15.3.4 本节练习
- 简答:pre-migrate 与 post-migrate 的典型分工各举一例。
- 情景:表 5000 万行 加
NOT NULL列,直接UPDATE全表有何风险? - 判断:所有数据修复都应在 SQL 迁移脚本完成。( )
参考答案提示:2. 长锁、磁盘、回滚困难。3. 错,可用 ORM、服务器动作、分批任务等。
15.4 数据备份与恢复
15.4.1 知识要点
pg_dump:逻辑备份;-Fc自定义格式便于pg_restore选择性恢复。- filestore:
ir.attachment等二进制可能存 文件系统;备份必须 DB + filestore 一致(或明确仅用 DB 内存储策略)。 - Odoo 命令:
db.dump/db.restore(以 CLI 文档为准)封装常见操作。 - RPO:最多丢多久数据;RTO:多久恢复服务。
15.4.2 案例
# 示例:自定义格式备份
pg_dump -h localhost -U odoo -Fc mydb > mydb_$(date +%Y%m%d).dump
# 恢复到新库名
createdb mydb_restored
pg_restore -d mydb_restored mydb_20260329.dump
filestore 同步(示意):
rsync -av /var/lib/odoo/filestore/mydb/ /backup/filestore/mydb/
15.4.3 截图占位


15.4.4 本节练习
- 实操:在 测试机 从 dump 恢复库并 登录验证 附件图片是否可读。
- 简答:仅恢复 DB、不恢复 filestore 会导致什么现象?
- 简答:每日全量 + 连续归档(WAL) 对 RPO 的意义?
15.5 只读查询 API(了解)
15.5.1 知识要点
较新版本提供 execute_query 一类 只读 SQL 入口(名称与签名以文档为准),在 受限上下文 中返回字典行,用于报表与分析;仍须注意 权限与数据范围由业务封装。
15.5.2 本节练习
- 拓展:在官方文档搜索
execute_query,记录其与普通cr.execute的差异一句。
本章综合练习
- 事故演练:误执行
DELETE删 1 万行——写出 恢复步骤(从备份时间点、filestore、业务校验到沟通)。 - 选型:同一聚合报表,
read_group与 手写 SQL GROUP BY 的取舍表(权限、性能、可维护性三行)。 - 设计:为「月度借阅统计」写 ORM 方案 与 SQL 方案 提纲各一条。
- 合规:备份文件含 个人数据 时的 加密与访问控制 要点(简答)。
本章对应白皮书目录:第十五章 数据库操作。