使用Flyway执行PostgreSQL迁移脚本时设置变量报语法错误
问题根因
@set 不是PostgreSQL数据库服务端支持的标准SQL语法,它是psql(PostgreSQL官方命令行客户端)、DBeaver等数据库客户端工具自行实现的客户端侧专有命令:这类命令只会在客户端本地被解析处理,根本不会发送到PostgreSQL服务端执行。
Flyway是通过JDBC驱动直接将迁移脚本中的语句发送给PostgreSQL服务端执行,它既不识别这类客户端专有命令,也不会做对应解析转换,服务端收到以@开头的非法SQL语句时,就会直接抛出语法错误。
修复方案
你可以根据实际场景选下面任意一种方案处理:
- 优先使用Flyway原生占位符能力替代客户端变量
这是和Flyway迁移流程适配度最高的方案,完全不依赖特定客户端能力。直接在Flyway配置文件、启动参数、环境变量中定义占位符即可:
迁移脚本中直接通过# flyway配置示例 flyway.placeholders.TEST=testing by us${TEST}格式引用对应值,Flyway执行迁移时会自动完成值替换,再将合法SQL发送给数据库执行,不会触发语法错误。 - 使用PostgreSQL服务端原生语法定义变量
如果需要在SQL脚本内部完成变量定义,直接使用PostgreSQL服务端可识别的语法,不要依赖客户端元命令:-- 方式1:定义会话级自定义变量 SET my.custom.test = 'testing by us'; -- 后续取值方式 SELECT current_setting('my.custom.test'); -- 方式2:在PL/pgSQL代码块中定义局部变量 DO $$ DECLARE TEST text := 'testing by us'; BEGIN -- 此处编写需要用到TEST变量的业务逻辑 RAISE NOTICE 'Current variable value: %', TEST; END $$; - 特殊场景下调整执行链路(不推荐)
如果脚本中存在大量无法改造的psql专有命令,不要让Flyway直接执行这类脚本,可通过Flyway的回调机制,在迁移节点调用本地psql客户端进程执行对应脚本。但这种方案会强依赖执行环境的psql安装配置,破坏迁移脚本的跨环境一致性,非必要不使用。
内容的提问来源于stack exchange,提问作者Minesh
相关产品推荐
相关产品推荐

