免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

19-accept与reject

19-accept与reject 19-accept与reject提交与回滚的对称设计accept是提交成功后确认变更reject是放弃变更回滚。两个方法看似对称实现却不对称——reject要处理三种行的三种命运accept只需要归零。而且这两个方法都修过bugP1-2.3/2.4。这篇讲对称设计的不对称实现和修复历史。文章目录19-accept与reject提交与回滚的对称设计一、两种清算的调用时机二、accept三步归零P1-2.4修复accept没清originals三、reject三种行三种命运为什么倒序遍历P1-2.3修复reject恢复用了clear的错值四、reject的已知边界DELETE行不回primary五、对称设计的隐喻源码browise-data/src/main/java/com/browise/data/RowSet.javaL148-189修复记录BROWISE-STATUS.md 第五节 P1-2.3 / P1-2.4一、两种清算的调用时机用户编辑行集 │ ├── 提交commonSave到后端 │ ├── 成功 → accept() 变更已成事实 │ └── 失败 → reject() 服务器拒绝界面回滚 │ └── 取消按钮 → reject() 用户放弃编辑谁调用——前端useRowSet有同名方法第44篇通过HTTP结果分支code0调acceptChanges()非0调rejectChanges()。后端RowSet的accept/reject主要服务服务端批处理场景导入、批量核定——Controller里load→改→save→accept的流水线。二、accept三步归零publicvoidaccept(){for(Rowrow:primary){row.setStatus(RowStatus.NONE);// ①状态归零if(row.getOriginals()!null){row.getOriginals().clear();// ②旧值清空}}delete.clear();// ③删除缓冲清空filter.clear();}语义从现在起当前数据就是原始数据。INSERT行→NONE新行入库成功它不再是新增是库里的正式行UPDATE行→NONE_o清空修改已生效旧值失去意义delete缓冲的行数据库里已删缓冲清掉防止重复提交accept不知道也不关心数据库发生了什么——调用方保证提交确实成功了才调它。它只是把内存状态和数据对齐。P1-2.4修复accept没清originals修复前的bug——accept只改了status没清original// 修复前for(Rowrow:primary){row.setStatus(RowStatus.NONE);// 只归零状态}后果提交成功后再修改同一行——setItemValue发现statusNONE转UPDATE正常但original里还留着上一轮的旧值异常第二轮的_o锚在了第一轮之前的值上——如果第二轮reject行会恢复到两轮之前的值。审计模块抓diff也受害——diff对比的是getOriginal跨轮的旧值污染变更记录。修复就是加那两行clear()。教训状态机复位必须复位全部状态承载——status和original是一对只复位一个就埋雷。三、reject三种行三种命运publicvoidreject(){// ①倒序移除INSERT行for(intiprimary.size()-1;i0;i--){if(primary.get(i).getStatus()RowStatus.INSERT){primary.remove(i);}}// ②UPDATE行整体恢复for(Rowrow:primary){if(row.getStatus()RowStatus.UPDATE){MapString,Objectoriginalsrow.getOriginals();if(originals!null!originals.isEmpty()){row.getMap().clear();row.getMap().putAll(originals);// data整体替换为originals}row.getOriginals().clear();row.setStatus(RowStatus.NONE);}}delete.clear();filter.clear();}三种行的命运行状态reject行为语义INSERT从primary移除从未入库回滚从未存在UPDATEdata恢复为_o状态归NONE修改撤销回到加载时刻DELETEdelete缓冲缓冲清空行不回primary⚠️ 见下文为什么倒序遍历for(intiprimary.size()-1;i0;i--){if(...)primary.remove(i);// 正向遍历边删会跳元素}ArrayList删除元素后右侧元素左移——正向遍历时i跳过了被删元素后面那个。倒序删除是List遍历删除的标准姿势。这不是设计亮点是Java基础——但在压力下写错的比例高得惊人正序删除的bug在很多项目里出现过。P1-2.3修复reject恢复用了clear的错值修复前的bug——reject恢复UPDATE行时// 修复前示意row.getMap().clear();// 先清空data// ...中间某个异常路径或逻辑错误导致putAll的不是originalsBROWISE-STATUS记录为恢复原始值时错误clear改用original恢复。修复后用clear()putAll(originals)整体替换——先把data清干净再灌original两步之间不存在中间状态单线程下原子完成。这个bug的杀伤力reject后界面数据变成空行旧值混合——用户点取消数据莫名其妙丢了一半。四、reject的已知边界DELETE行不回primary第18篇留的问题——delete.clear()直接清空被删的行没有恢复到primary。对照PB DataWindowreject时delete缓冲的行会回到primary撤销删除。browise当前行为reject后删除不撤销——用户删了三行又点取消那三行界面上也消失了要重新查询才能看到。这是已知的语义取舍还是未修的缺陷——从代码注释和测试看是有意的简化删除操作在UI上通常有确认弹窗“确定删除这3条吗”确认后的删除是坚定的——reject只撤销未确认的编辑增/改不撤销已确认的删除。如果业务需要删除也可撤销——把delete.clear()改成遍历delete缓冲行状态复位NONE塞回primary即可8行代码。协议留了这个扩展点只是默认行为选择了简单。五、对称设计的隐喻accept: 内存状态 → 向数据库对齐数据库是真了内存认账 reject: 内存状态 → 向加载时刻对齐数据库没变内存回到起点两者都是单向清算——accept不需要知道数据库怎么变的它相信成功reject不需要知道编辑过程多复杂_o只记了最初值。脏标记协议的最小完备性在这里兑现只要_t/_o两个锚点任何编辑序列都能被这两个方法干净清算。✅ 亮点accept三步归零与reject三种行三种命运的对照、P1-2.4复位必须复位全部状态承载的教训、P1-2.3整体替换避免中间状态、倒序删除的标准姿势、DELETE行不回primary的语义取舍。适合实现编辑回滚的人。扩展方向第23篇commonSave、第44篇前端acceptChanges/rejectChanges镜像、第53篇审计对_o的消费。
返回列表