Java中使用Liquibase回滚Postgres为何未清除测试持久化数据
Liquibase回滚无法清除Hibernate持久化测试数据的核心原因
根本原因
- Liquibase的回滚操作仅作用于其自身跟踪的变更集,完全覆盖不到业务侧直接执行的DML
Liquibase的设计逻辑是:只识别、回滚那些通过自身update命令执行的、写入DATABASECHANGELOG系统表的变更(比如建表、加字段、预定义的初始化数据等)。你通过Hibernate直接持久化的ThingEntity属于测试运行时产生的动态业务数据,没有被Liquibase的变更跟踪体系记录,自然不在回滚的作用范围内。 - 回滚后标签消失的现象完全符合Liquibase的设计逻辑
你在初始化完所有库结构后执行打标签操作,之后没有再通过Liquibase执行任何变更集——从Liquibase的视角看,数据库状态在打标签之后没有任何它能感知到的变化。此时调用rollback("initialised")时:- Liquibase会检索所有时间点晚于该标签、且由自身执行的变更集,发现可回滚的变更集为空,因此不会对实际业务表做任何修改
- 按照回滚流程的固定设计,Liquibase会删除该标签在系统表中的记录,最终就出现了“标签被移除、但业务数据完全保留”的现象。
适配组件测试场景的可行方案
- 优先采用测试级事务回滚的方案
不需要在每个测试用例中提交Hibernate的事务,让整个测试用例的执行全程运行在一个数据库事务上下文中,测试执行完成后直接回滚该事务,即可一次性清除所有测试期间产生的业务数据。这种方式的性能远优于逐表清理或Liquibase回滚,也能和Kotest的生命周期钩子很好适配。 - 如果需要同步清理测试期间的结构变更,可搭配Liquibase基线标签能力
全测试套件启动时,完成所有库结构的初始化后打baseline基线标签,每个测试用例执行完成后按两步清理:- 先将Liquibase回滚到
baseline标签,清除测试期间通过Liquibase执行的所有结构变更 - 再通过Postgres的
TRUNCATE TABLE ... RESTART IDENTITY CASCADE语句清空所有业务表,清除测试产生的动态数据
- 先将Liquibase回滚到
- 不建议将测试动态数据写入Liquibase变更集
虽然这种方式能让Liquibase跟踪到数据变更、实现回滚,但会大幅提升测试维护成本,测试过程中动态生成的业务数据也很难全部通过静态changelog描述实现,性价比极低。
内容的提问来源于stack exchange,提问作者MysteriousWaffle
相关产品推荐
相关产品推荐

