本文详解 odoo 中连续 sql update 语句的执行机制、潜在数据覆盖风险,并推荐基于 orm 的安全、可维护替代实现方式。
在 Odoo 开发中,直接使用 self.env.cr.execute() 执行原始 SQL 虽然高效,但极易引入逻辑隐患和安全漏洞。你提供的两段顺序 SQL 更新看似清晰,实则暗含关键问题:
-- 第一条:将关联有效销售单的会员状态设为 'confirmed'
UPDATE gym_membership SET state = 'confirmed'
WHERE id IN (
SELECT gym_membership_id FROM sale_order
WHERE gym_membership_id IN (
SELECT id FROM gym_membership
WHERE state = 'finished'
AND is_sessions_generated = False
AND membership_type IN ('class','private')
)
);
-- 第二条:将所有符合条件的 'finished' 会员设为 'draft'
UPDATE gym_membership SET state = 'draft'
WHERE state = 'finished'
AND is_sessions_generated = False
AND membership_type IN ('class','private');
执行顺序与隐性覆盖风险
这两条语句确实在同一数据库游标(self.env.cr)中严格串行执行——第一条完成后,第二条才开始。但由于它们操作同一张表的同一字段(state),第二条会无差别覆盖第一条已更新的记录。例如:某条 gym_membership 记录满足第一条子查询条件(被关联到 sale.order),被设为 ‘confirmed’;但它同时也满足第二条的 WHERE 条件(state=’finished’, is_sessions_generated=False, membership_type IN (‘class’,’private’)),因此紧接着又被覆写为 ‘draft’。最终结果与业务预期(“有订单的升为 confirmed,其余同条件的降为 draft”)完全相悖。