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

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解析失败发生在事务中间,怎么保证不残留脏数据
解析阶段(如用 SAXParser 或 JAXBContext)抛异常时,如果已执行过 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,改用REUSE或SIMPLE;或确保在事务方法末尾显式调用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) 的日志记录方法,它会在独立事务中提交,即使外层回滚,日志仍会写入——这类“半截日志”会让排查变得混乱。










