IDEA调试模式启动Spring Boot时Liquibase重复执行变更集问题
我之前也碰到过类似的诡异问题,结合Liquibase和Spring Boot的工作机制,给你几个排查和解决的方向:
1. 确认变更集的ID和Author是固定值
Liquibase判断变更集是否已执行的核心依据是id+author+filename的组合。如果你的变更集里用了动态生成的ID(比如嵌入了时间戳、环境变量),调试模式和正常模式下可能生成不同的标识,导致Liquibase认为是全新的变更集。
正确示例:
<changeSet id="init_user_table_v1" author="your_team"> <createTable tableName="user"> <column name="id" type="BIGINT" autoIncrement="true"> <constraints primaryKey="true"/> </column> <column name="username" type="VARCHAR(50)" constraints nullable="false"/> </createTable> </changeSet>
避免使用${timestamp}这类动态值作为变更集ID,确保三个标识字段在任何启动模式下都完全一致。
2. 检查两种模式下的数据源配置是否一致
很多时候调试模式会加载不同的配置文件(比如application-debug.yml而非默认的application.yml),如果配置的数据源URL、库名不一样,databasechangelog表就不在同一个数据库里,自然识别不到已执行的变更记录。
你可以在启动时打印当前数据源信息来验证:
@Autowired private DataSource dataSource; @PostConstruct public void verifyDataSource() { try (Connection conn = dataSource.getConnection()) { System.out.println("当前连接的数据库: " + conn.getMetaData().getURL()); } catch (SQLException e) { e.printStackTrace(); } }
确保调试和正常模式下输出的数据库URL完全相同。
3. 核对Liquibase的上下文(Context)配置
如果你的变更集指定了特定的执行上下文(比如<changeSet ... context="prod">),而两种启动模式下激活的上下文不一致,也会导致Liquibase误判变更集状态。
检查配置文件中的上下文设置:
# application.properties spring.liquibase.contexts=dev
确保调试模式下的配置(比如application-debug.properties)中,spring.liquibase.contexts的值和正常模式完全一致。
4. 检查调试模式下的事务提交状态
调试时如果暂停时间过长、或者调试器打断了事务流程,可能导致Liquibase执行变更集后,事务没有正常提交,databasechangelog表中不会生成对应的记录。
你可以手动查询数据库的databasechangelog表,确认调试模式执行后,对应的变更集记录是否存在且EXECUTION_STATUS为SUCCESS。如果记录缺失,检查Spring的事务配置,或者调整Liquibase的rollback-on-error等参数。
5. 开启Liquibase调试日志排查细节
如果以上方法都没解决问题,建议开启Liquibase的DEBUG日志,查看它判断变更集是否已执行的具体逻辑:
spring.liquibase.log-level=DEBUG
启动后关注日志中类似Checking for change set [id:xxx, author:xxx, filename:xxx]的条目,对比日志中的标识和databasechangelog表中的记录是否完全匹配,就能定位到具体的判断差异。
内容的提问来源于stack exchange,提问作者Xtroce

