Excel、CSV 与导入导出:大数据文件怎样校验、分批和回滚
十万行 Excel 导入在第九万行遇到非法金额,整个事务回滚了四十分钟;用户修正后重新上传,又重复写入前八万条外部通知。问题不只是文件大,而是解析、验证、提交和副作用没有阶段边界。可靠导入先把文件变成一组可追踪行结果,再把合法批次变成幂等业务动作,不能让 Workbook 对象同时承担事务和错误报告。
Apache POI 为 XSSF 提供 SAX 事件读取,并用 SXSSF 滑动窗口降低写出内存;流式 API 仍可能把 shared strings、样式、合并单元格或临时 XML 留在内存/磁盘。CSV 也不是简单 split(','):引号、转义、换行、编码和空值都属于格式语义。
从请求入口画出真实字节路径
创建 importId 并保存源对象 version、checksum、Schema version、编码、状态与 owner。第一阶段流式读取行,规范化表头和单元格类型,生成 rowNumber、businessKey、payloadHash 与校验错误;错误达到上限后仍要安全停止并关闭解析器。第二阶段按固定行数和字节数批量提交,每批用 importId+batchNo 唯一约束,并让业务表以稳定键防重复。checkpoint 只在事务提交后推进,重启从最后一个已提交 batch 继续。
关键提交窗口怎样形成
日期、金额、ID、前导零、科学计数和公式结果不能靠 getStringCellValue 猜测;Schema 明确期望类型、locale、时区、舍入和空值。公式单元格既可能读取缓存结果,也可能需要计算引擎,外部链接与宏更是安全边界。导出则先固定查询快照或游标水位,逐页读取并流式写出;如果数据在导出中变化,文件必须标注 snapshot/version,不能声称是同一时刻全量。
六个状态节点逐段落地
固定源文件版本
进入“固定源文件版本”时记录 fileId/uploadId、objectVersion、实际字节、checksum、owner、状态版本与 deadline。正向实验断言字节、状态和业务引用守恒;反向实验在流关闭、对象提交或状态回写前后制造断连与超时,确认临时资源有归宿、UNKNOWN 能对账、迟到写不能覆盖新版本。
流式解析行
进入“流式解析行”时记录 fileId/uploadId、objectVersion、实际字节、checksum、owner、状态版本与 deadline。正向实验断言字节、状态和业务引用守恒;反向实验在流关闭、对象提交或状态回写前后制造断连与超时,确认临时资源有归宿、UNKNOWN 能对账、迟到写不能覆盖新版本。
执行 Schema 校验
进入“执行 Schema 校验”时记录 fileId/uploadId、objectVersion、实际字节、checksum、owner、状态版本与 deadline。正向实验断言字节、状态和业务引用守恒;反向实验在流关闭、对象提交或状态回写前后制造断连与超时,确认临时资源有归宿、UNKNOWN 能对账、迟到写不能覆盖新版本。
提交幂等批次
进入“提交幂等批次”时记录 fileId/uploadId、objectVersion、实际字节、checksum、owner、状态版本与 deadline。正向实验断言字节、状态和业务引用守恒;反向实验在流关闭、对象提交或状态回写前后制造断连与超时,确认临时资源有归宿、UNKNOWN 能对账、迟到写不能覆盖新版本。
推进 Checkpoint
进入“推进 Checkpoint”时记录 fileId/uploadId、objectVersion、实际字节、checksum、owner、状态版本与 deadline。正向实验断言字节、状态和业务引用守恒;反向实验在流关闭、对象提交或状态回写前后制造断连与超时,确认临时资源有归宿、UNKNOWN 能对账、迟到写不能覆盖新版本。
生成错误或导出
进入“生成错误或导出”时记录 fileId/uploadId、objectVersion、实际字节、checksum、owner、状态版本与 deadline。正向实验断言字节、状态和业务引用守恒;反向实验在流关闭、对象提交或状态回写前后制造断连与超时,确认临时资源有归宿、UNKNOWN 能对账、迟到写不能覆盖新版本。
文件不是一个字段,而是一条跨资源事务
上传成功至少经过 RECEIVING、QUARANTINED、VALIDATING、READY 或 REJECTED,删除经过 DELETE_REQUESTED、HELD、DELETING 与 DELETED。每次外部调用都可能出现“存储成功但响应丢失”,因此 UNKNOWN 是合法中间态;reconciler 用稳定 key/version 和 checksum 查询事实,再推进数据库,而不是重做一次覆盖写。
流式只成立在所有缓冲都有上限时
完整性、安全性和业务有效性是三条证据
下载也是受控数据流
观测与对账要覆盖数据库和对象存储两边
发布和回滚必须保持对象格式与状态兼容
反向实验要击中资源与状态的交界
CSV 导出以 =、+、-、@ 开头的用户字段可能在表格软件中作为公式执行,面向人工打开的文件需要安全转义策略,同时保留机器接口的原始数据契约。SXSSF 会生成临时文件,必须 dispose/close,并监控临时盘;共享字符串和过多 CellStyle 仍可能吃满堆。逐行查数据库会形成 N+1,整表预加载又失去流式优势,批量预取与缓存上限要一起设计。 实验固定文件字节、并发、缓冲、存储版本和故障点,保存容器临时目录、对象元数据、数据库状态与连接水位。修复后复用相同样本,既证明错误被拒绝或恢复,也证明堆、临时盘、parts 和连接回到稳定基线。
两个 Java 17 模型固定量化见证
模型执行真实计算和断言,把框架日志容易掩盖的流量或状态不变量压缩成确定输出。
javac --release 17 -Xlint:all -Werror examples/backend-development/file-storage/excel-csv-import-export/CsvImportLedgerDemo.java examples/backend-development/file-storage/excel-csv-import-export/ExportWindowDemo.java
java -cp examples/backend-development/file-storage/excel-csv-import-export CsvImportLedgerDemo
java -cp examples/backend-development/file-storage/excel-csv-import-export ExportWindowDemorows=10 valid=8 invalid=2 batchesCommitted=2 replayedBatches=1 businessWrites=8 checkpoint=10 converged=true
snapshotMaxId=100 pages=4 rowsExported=100 concurrentNewRows=7 includedNewRows=0 consistent=true工程验证再替换成真实 Servlet、对象存储、解析器与数据库,保留相同 fileId/uploadId、状态迁移和输出不变量;模型字符串不能替代实际断连、覆盖、扫描和清理实验。
架构选择由数据流和授权新鲜度决定
小而强交互的模板可用 XSSF 全模型;大 Excel 读取用 SAX,大写出用 SXSSF;机器交换优先 CSV 或明确 Schema 的结构化格式;需要复杂失败恢复时先落原始文件,再异步导入并提供错误文件。全有或全无只适合可承受的大事务,更多业务应选择批次提交、幂等和显式部分成功语义。
发布门禁要证明生命周期闭环
发布时必须守住“解析错误可定位、已提交批次可重放,导入与导出都绑定明确源版本和数据快照”。验收同时覆盖正常、慢、断连、重复、结果未知、权限撤销和清理恢复;核对接收字节、最终对象、业务引用、临时对象和删除结果。任何临时放宽都绑定 owner、影响前缀、补偿扫描和到期条件,过期自动阻断。
