如何在审批完成前暂存应用与数据库中的未提交修改数据
针对CMS审核流暂存未生效修改的落地方案(Oracle + Java 技术栈)
一、核心方案选型对比
你提到的「每个业务表对应临时副本表」的方案可行但不是最优,冗余度高、后续维护成本大,仅适合业务表极少的极简场景,业务量较大的情况下不推荐。目前主流成熟方案如下:
方案1:通用审核变更快照表(推荐度最高)
不需要为每个业务表单独建临时表,统一用一张通用表存储所有待审核的变更内容,Oracle的原生JSON数据类型完全可以支撑非结构化的修改快照存储,表结构设计参考:
CREATE TABLE AUDIT_CHANGE_SNAPSHOT ( SNAPSHOT_ID NUMBER PRIMARY KEY, BUSINESS_TYPE VARCHAR2(64) NOT NULL, -- 对应业务类型:如文章、商品、栏目 BUSINESS_ID VARCHAR2(64) NOT NULL, -- 对应主业务记录的主键ID OPERATE_TYPE VARCHAR2(16) NOT NULL, -- 操作类型:新增/修改/删除 CHANGE_CONTENT CLOB CHECK (CHANGE_CONTENT IS JSON), -- 存储全量/增量修改的JSON数据 OPERATOR_ID VARCHAR2(64) NOT NULL, -- 提交修改的用户ID SUBMIT_TIME TIMESTAMP NOT NULL, AUDIT_STATUS VARCHAR2(16) DEFAULT 'WAIT_AUDIT', -- 审核状态:待审核/通过/驳回/已撤销 AUDITOR_ID VARCHAR2(64), AUDIT_TIME TIMESTAMP, AUDIT_REMARK VARCHAR2(512) ); -- 新增常用查询索引 CREATE INDEX IDX_AUDIT_BUSINESS ON AUDIT_CHANGE_SNAPSHOT(BUSINESS_TYPE, BUSINESS_ID, AUDIT_STATUS);
- 优势:
- 结构通用,不需要随业务表新增、调整同步修改表结构
- Oracle对JSON类型的查询、解析性能完全满足常规业务需求,Java侧可以直接用Jackson序列化/反序列化修改内容,不管是单字段修改还是全量多字段修改都能支持
- 审核流逻辑完全和业务逻辑解耦,驳回直接修改审核状态即可,审核通过后再把JSON里的内容反序列化,更新到对应主业务表
- 适用场景:90%以上的CMS审核场景都可使用,尤其适合业务表多、修改字段不固定的场景
方案2:业务表单版本字段+状态标识
如果你的业务表结构本身变动少,且需要支持多版本回溯,可以在原有业务表上新增3个字段:
VERSIONNUMBER:版本号,每次提交修改生成新版本AUDIT_STATUSVARCHAR2(16):审核状态LATEST_EFFECTIVECHAR(1):是否是当前生效版本
用户提交修改时直接在原业务表插入一条新版本的记录,生效状态设为N,审核通过后把旧版本的生效标识改N,新版本改Y即可。- 优势:不需要额外建表,数据回溯方便,查询逻辑简单
- 劣势:业务表主键逻辑要调整,删除操作的逻辑需要单独处理,不适合主键不能重复的业务场景
方案3:Java侧缓存中间态
如果审核周期短、并发量低,也可以把未审核的修改存在Redis的Hash结构里,key用audit:{businessType}:{businessId},value存修改内容的JSON,设置对应的过期时间(比如最长7天,超过未审核自动过期驳回)。
- 优势:不需要修改数据库结构,读写性能高
- 劣势:Redis是内存数据库,有丢数据风险,不适合审核周期超过3天、数据要求高可靠的场景
二、常见问题解答
- 每个业务表对应一张临时表的方案可行吗?
如果你的业务表数量少于10张,且后续不会新增业务表,可以使用,优势是字段类型和主表完全对齐,不需要做JSON序列化反序列化的转换;但如果业务表多,后续维护成本极高,每新增一个业务表、修改一个字段都要同步修改临时表,不推荐。 - Java侧的适配方案
可以直接基于Spring Boot做通用的审核切面,所有需要审核的修改接口加自定义注解@NeedAudit,切面拦截请求后把修改内容序列化后直接写入AUDIT_CHANGE_SNAPSHOT表,不需要每个业务接口单独写审核逻辑,复用度很高。 - Oracle侧的性能优化
如果变更快照表数据量超过千万级,可以按SUBMIT_TIME做分区表,定期归档已经审核完成的历史数据,查询性能不会有明显下降。
内容的提问来源于stack exchange,提问作者user2710961
相关产品推荐
相关产品推荐

