
在 spring boot 集成测试中,当使用嵌入式 postgresql(如 zonkyio/embedded-postgres)配合 liquibase 时,schema.sql 默认不会自动执行;本文介绍如何通过 liquibase 变更集安全、可控地替代 schema.sql,实现数据库创建、角色初始化等需脱离事务的操作。
在 spring boot 集成测试中,当使用嵌入式 postgresql(如 zonkyio/embedded-postgres)配合 liquibase 时,schema.sql 默认不会自动执行;本文介绍如何通过 liquibase 变更集安全、可控地替代 schema.sql,实现数据库创建、角色初始化等需脱离事务的操作。
Spring Boot 的 schema.sql 和 data.sql 机制仅对 Spring JDBC 初始化器(DataSourceInitializer)生效,且不适用于 Liquibase 管理的数据源场景——一旦启用 Liquibase(如通过 spring.liquibase.enabled=true),Spring 会自动禁用默认的 SQL 脚本执行逻辑。因此,将建库、建角色等 DDL 操作硬编码进 schema.sql 并期望其在嵌入式 PostgreSQL 启动后、Liquibase 运行前执行,本质上是不可靠的。
解决思路是:将初始化逻辑内聚到 Liquibase 变更集中,并显式控制其执行时机与事务行为。Liquibase 提供了 runInTransaction="false" 属性,专为无法在事务中执行的语句(如 CREATE DATABASE、CREATE ROLE、DROP DATABASE)设计——这些命令在 PostgreSQL 中要求处于非事务块(autocommit mode)。
以下是一个典型示例,适用于测试环境专用的初始变更集(建议置于 src/test/resources/db/changelog/db.init.xml 或对应 YAML/JSON 格式):
<?xml version="1.0" encoding="UTF-8"?><databasechangelog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.27.xsd"><!-- 注意:必须 runInTransaction="false",否则 CREATE DATABASE 会失败 --><changeset id="init-create-database" author="test" runintransaction="false"><sql>CREATE DATABASE myapp_test;</sql><rollback>SELECT 1;</rollback></changeset><changeset id="init-create-role" author="test" runintransaction="false"><sql>CREATE ROLE test_user WITH LOGIN PASSWORD 'test123';</sql><rollback>DROP ROLE IF EXISTS test_user;</rollback></changeset><!-- 后续常规迁移(如建表、索引)可保持默认事务模式 --><changeset id="init-create-tables" author="test"><createtable tablename="users"><column name="id" type="BIGSERIAL" primarykey="true"></column><column name="username" type="VARCHAR(64)"></column></createtable></changeset></databasechangelog>
⚠️ 关键注意事项:
- runInTransaction="false" 的变更集不能回滚(Liquibase 不支持非事务操作的自动回滚),因此
标签仅作占位或用于人工清理,不应依赖其自动化; - 嵌入式 PostgreSQL 实例启动后,默认连接的是 postgres 数据库;CREATE DATABASE 成功后,需确保后续变更集连接到新建数据库(可通过 spring.datasource.url=jdbc:postgresql://localhost:5432/myapp_test 在测试配置中指定);
- 推荐将此类初始化变更集单独拆分并优先加载(例如在 spring.liquibase.change-log=classpath:db/changelog/db.init.xml 中显式指定),避免与主业务迁移混杂;
- 若项目已使用 YAML 格式 changelog,对应写法为:
- changeSet: id: init-create-database author: test runInTransaction: false changes: - sql: CREATE DATABASE myapp_test;
总结:放弃依赖 schema.sql 是更健壮的选择。将数据库基础设施初始化逻辑纳入 Liquibase 管控体系,不仅能精准控制执行顺序与上下文,还能与测试生命周期无缝集成,同时保持迁移脚本的可移植性与可审计性。











