ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

业务方案:先记操作流水 → 走审批 → 审批通过后正式生效

业务方案:先记操作流水 → 走审批 → 审批通过后正式生效 目录业务概述数据库设计核心 3 张表1. 主业务表比如goods_price 商品价格表2. 操作变更流水表operation_log核心3. 审批任务表approval_task工作流最小实现复杂场景接入 Flowable完整业务流程代码逻辑步骤 1用户提交变更申请事务 1步骤 2审批人处理审批同意 / 驳回分支 A审批【驳回】事务 2分支 B审批【通过】事务 3重点方案变种对比方案 A上面这套【快照流水 审批后更新主表】✅推荐方案 B主表保留多版本主表新增一条版本记录旧版本标记失效方案 C不维护主表业务查询时合并流水不推荐重点问题 边界处理业务概述核心规则用户提交变更先落操作流水记录状态 待审批此时业务实体本身不生效审批流程独立流转审批通过才把变更内容刷入主业务表状态改为生效审批驳回主业务数据不变流水标记驳回。典型场景合同变更、价格调整、权限变更、额度修改、订单改单。 核心目的留痕、可回溯、变更不即时生效审批是生效开关数据库设计核心 3 张表1. 主业务表比如goods_price 商品价格表真实生效的数据在这里审批未通过时本表不更新sqlCREATE TABLE goods_price ( id BIGINT PRIMARY KEY AUTO_INCREMENT, goods_id BIGINT NOT NULL COMMENT 商品ID, price DECIMAL(18,2) NOT NULL COMMENT 生效价格, effective_time DATETIME COMMENT 生效时间, status TINYINT COMMENT 0失效 1生效, create_time DATETIME DEFAULT NOW(), update_time DATETIME DEFAULT NOW() );2. 操作变更流水表operation_log核心用户提交修改先插入这张表保存本次要修改的目标值、变更前后快照、审批状态sqlCREATE TABLE operation_log ( id BIGINT PRIMARY KEY AUTO_INCREMENT, business_type VARCHAR(64) NOT NULL COMMENT 业务类型GOODS_PRICE, business_id BIGINT NOT NULL COMMENT 主业务ID对应goods_price.id, before_content TEXT COMMENT 变更前JSON快照, after_content TEXT COMMENT 申请变更后的JSON快照, apply_user BIGINT NOT NULL COMMENT 申请人, apply_time DATETIME DEFAULT NOW(), approval_status TINYINT NOT NULL COMMENT 0待审批 1审批通过 2审批驳回 3撤销申请, approval_user BIGINT COMMENT 审批人, approval_time DATETIME, approval_comment VARCHAR(512) COMMENT 审批意见, create_time DATETIME DEFAULT NOW(), update_time DATETIME DEFAULT NOW() );3. 审批任务表approval_task工作流最小实现复杂场景接入 Flowable记录每一条流水对应的审批节点、审批人sqlCREATE TABLE approval_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, operation_log_id BIGINT NOT NULL COMMENT 关联操作流水ID, node_name VARCHAR(64) NOT NULL COMMENT 审批节点, approver BIGINT NOT NULL COMMENT 审批人ID, task_status TINYINT NOT NULL COMMENT 0待处理 1同意 2驳回, task_sort INT COMMENT 审批顺序, create_time DATETIME DEFAULT NOW() );完整业务流程代码逻辑步骤 1用户提交变更申请事务 1查询当前主业务表旧数据序列化为beforeContent用户提交新参数组装afterContent开启事务插入operation_log状态 待审批根据审批规则生成审批任务approval_task✅主业务表【不做任何更新】事务提交返回申请单号流水 ID关键点此时查询主业务数据还是旧值变更只保存在流水里。伪代码javaTransactional(rollbackFor Exception.class) public Long applyChange(GoodsPriceDTO dto) { // 1.查询当前生效数据 GoodsPrice oldData goodsPriceMapper.selectById(dto.getGoodsId()); String beforeContent JSON.toJSONString(oldData); // 2.组装新变更数据快照 GoodsPrice newData BeanUtil.copyProperties(dto, GoodsPrice.class); String afterContent JSON.toJSONString(newData); // 3.写入操作流水待审批 OperationLog log new OperationLog(); log.setBusinessType(GOODS_PRICE); log.setBusinessId(oldData.getId()); log.setBeforeContent(beforeContent); log.setAfterContent(afterContent); log.setApprovalStatus(0); //待审批 log.setApplyUserId(getCurrentUserId()); operationLogMapper.insert(log); // 4.生成审批任务 ListApprovalTask taskList buildApprovalTask(log.getId()); approvalTaskMapper.insertBatch(taskList); return log.getId(); }步骤 2审批人处理审批同意 / 驳回分支 A审批【驳回】事务 2更新operation_log状态 驳回填写审批人、审批意见更新approval_task当前节点状态为驳回后续节点作废主业务表不修改事务提交业务保持旧数据流水永久留痕分支 B审批【通过】事务 3重点如果是多级审批需要判断是否是最后一级审批节点全部节点同意才触发生效javaTransactional(rollbackFor Exception.class) public void approve(Long logId, boolean pass, String comment) { OperationLog log operationLogMapper.selectById(logId); if (!pass) { // 驳回逻辑 log.setApprovalStatus(2); log.setApprovalComment(comment); operationLogMapper.updateById(log); // 更新审批任务状态 approvalTaskMapper.rejectTask(logId); return; } // 判断是否所有审批节点全部通过 boolean allApproved approvalTaskMapper.checkAllApproved(logId); if (!allApproved) { // 不是最后一级只更新当前审批任务不刷主表 approvalTaskMapper.passCurrentTask(logId); return; } // 全部审批完成开始生效把afterContent刷入主业务表 log.setApprovalStatus(1); log.setApprovalTime(LocalDateTime.now()); operationLogMapper.updateById(log); // JSON快照转实体更新主业务表 GoodsPrice target JSON.parseObject(log.getAfterContent(), GoodsPrice.class); goodsPriceMapper.updateById(target); }方案变种对比方案 A上面这套【快照流水 审批后更新主表】✅推荐适用变更字段不多、变更一次性生效查询主表就是最新生效数据。 优点业务查询简单历史变更全部存在流水审计友好。 缺点变更字段多的时候JSON 快照排查麻烦。方案 B主表保留多版本主表新增一条版本记录旧版本标记失效适用需要保留多版本历史例如合同。 逻辑审批通过新增一行主表版本旧版本置为失效不是原地 update。方案 C不维护主表业务查询时合并流水不推荐所有变更都存在流水业务查询主数据时合并所有已通过流水。 缺点查询逻辑复杂性能差适合极简单场景。重点问题 边界处理并发提交多份变更申请同一业务对象可以同时有多条「待审批」流水审批生效时需要考虑顺序。解决方案生效时加乐观锁主表加 version防止后审批的旧变更覆盖新变更。javaupdate goods_price set price?, versionversion1 where id? and versionoldVersion如果更新行数 0抛出异常数据已被其他变更覆盖。申请人撤销申请流水状态改为【撤销】审批任务作废主数据不变。审计追溯before_content和after_content是核心任何时候都可以查到这次修改前后的值。工作流选型审批节点固定、简单直接用上面approval_task表硬编码多级审批、动态审批人、会签或或签接入 Flowable / Camunda流水和工作流实例关联。生效时间控制延时生效业务需求审批通过但指定未来某个时间点才生效。 实现审批通过后主表不立即更新写入定时任务到时间执行更新流水标记 “待定时生效”。
返回列表