XML文件上传的事务管理 解析入库失败如何回滚

9次阅读

xml上传事务失效主因是事务边界未覆盖全流程,需确保解析、入库等操作在同一个@Transactional方法内,避免自调用失效、异常被捕获不抛出、非事务数据源及batch模式缓存导致回滚失败。

XML文件上传的事务管理 解析入库失败如何回滚

XML上传时事务没生效,数据部分写入了怎么办

XML文件上传后解析入库失败却无法回滚,通常不是因为“事务没加”,而是事务边界没包住整个解析+入库流程。spring@Transactional 默认只对 public 方法生效,且如果在同一个类里自调用(比如 upload()parseAndSave()),代理失效,事务就形同虚设。

  • 确保 XML 解析、数据库插入、状态更新等全部操作都在同一个 @Transactional 方法内,或通过 Spring 上下文重新获取代理对象调用
  • 避免在事务方法里手动捕获所有异常却不抛出——try-catch 吞掉异常会导致事务不回滚;如需处理,捕获后必须 throw new RuntimeException(e) 或声明该异常为 rollbackfor
  • 检查数据源是否为 Spring 管理的 DataSource,JDBC 直连 Connection 或使用非事务型连接池(如 HikariCP 配置了 autoCommit=true)会绕过事务控制

xml解析失败发生在事务中间,怎么保证不残留脏数据

解析阶段(如用 SAXParserJAXBContext)抛异常时,如果已执行过 INSERT 语句但事务尚未提交,理论上不会落库——前提是事务真正生效且未提前 flush。但有两类常见“伪残留”:

  • 自增主键被占用:mysql 在 INSERT 时即分配 ID,即使事务回滚,ID 也不会复用,造成空洞。这不是数据不一致,但可能影响业务预期
  • 唯一约束冲突前的中间状态:比如先插 A 表成功、再插 B 表失败,A 表数据会被回滚;但如果 A 表插入前做了 select FOR UPDATE 锁行,而解析卡住导致锁超时,可能引发其他请求阻塞
  • 建议在解析完成、校验通过后再执行批量 INSERT;或改用临时表 + 事务内重命名方式,避免解析中混杂 DML

mybatis 批量插入 XML 数据时事务回滚失效

SqlsessionTemplate@Mapper 接口做批量插入时,回滚失败常因以下配置问题:

  • ExecutorType.BATCH 模式下,MyBatis 缓存 SQL 并延迟执行,若在 batch 未 flush() 前异常退出,事务管理器看不到这些待执行语句,自然不触发回滚
  • 解决办法:不用 BATCH,改用 REUSESIMPLE;或确保在事务方法末尾显式调用 sqlSession.flushStatements()
  • Mapper XML 中的 如果生成了多条 INSERT,要确认每条都走的是同一个 SqlSession 实例,跨线程或手动 new SqlSession 会脱离事务上下文

文件已存、DB 回滚了,怎么防止重复上传和解析

事务只管数据库,不管文件系统。XML 上传成功但入库失败时,文件可能已落盘(如存到 /upload/20241105/xxx.xml),下次重试会重复解析——这需要应用层幂等控制:

  • 上传前先计算 XML 内容 MD5,作为业务主键或唯一索引字段(如 file_hash),入库前 SELECT count(*) WHERE file_hash = ?,存在则跳过
  • 不要依赖文件名判断唯一性——重传可能改名,或并发上传同名文件
  • 若必须保留原始文件,可将文件移动到 /success//failed/ 子目录,而不是删或覆盖;失败后清理动作放在事务外异步做,避免拖慢主流程

最易忽略的一点:事务传播行为。如果上传接口调用了另一个带 @Transactional(propagation = Propagation.REQUIRES_NEW) 的日志记录方法,它会在独立事务中提交,即使外层回滚,日志仍会写入——这类“半截日志”会让排查变得混乱。

text=ZqhQzanResources