Liquibase+H2DB测试报错:无法解析TIMESTAMP常量${now}
解决Liquibase在H2DB中${now}属性解析失败的问题
我之前也踩过一模一样的坑——PostgreSQL下Liquibase跑得顺风顺水,一到H2DB测试就因为${now}没被正确替换报错,折腾了好几天才摸清楚几个靠谱的解决办法,分享给你:
1. 改用Liquibase的defaultValueComputed属性
这是最省心的方案!直接把变更集里的defaultValue="${now}"换成defaultValueComputed="${now}",Liquibase会自动根据数据库类型,把${now}转换成对应的原生时间函数:
- PostgreSQL下生成
DEFAULT NOW() - H2DB下生成
DEFAULT CURRENT_TIMESTAMP
修改后的变更集示例:
<?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.9.xsd"> <changeSet id="create_test_table" author="your-name"> <createTable tableName="test_table"> <column name="id" type="BIGINT" autoIncrement="true"> <constraints primaryKey="true"/> </column> <!-- 改用defaultValueComputed适配多数据库 --> <column name="created_at" type="TIMESTAMP" defaultValueComputed="${now}"/> </createTable> </changeSet> </databaseChangeLog>
2. 开启H2DB的PostgreSQL兼容模式
如果不想改变更集,那就让H2DB模拟PostgreSQL的行为,这样它就能直接识别NOW()函数。只需要在测试的JDBC连接URL里加上MODE=PostgreSQL参数:
jdbc:h2:mem:testdb;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
这样Liquibase把${now}替换成NOW()后,H2DB就能正常解析,和PostgreSQL环境保持一致。
3. 为H2DB显式定义now属性
在测试环境的Liquibase配置文件(比如liquibase-test.properties)里,直接给now属性指定H2能识别的值:
now=CURRENT_TIMESTAMP
这样Liquibase在H2环境下会自动把${now}替换成CURRENT_TIMESTAMP,完美适配H2的语法。
4. 用上下文区分数据库(备选方案)
如果以上方法都不适用,可以给不同数据库写单独的变更集,用Liquibase的context和dbms预条件区分:
<!-- PostgreSQL专用变更集 --> <changeSet id="create_table_pg" author="your-name"> <preConditions onFail="MARK_RAN"> <dbms type="postgresql"/> </preConditions> <sql> CREATE TABLE test_table ( id BIGINT AUTO_INCREMENT PRIMARY KEY, created_at TIMESTAMP DEFAULT NOW() ) </sql> </changeSet> <!-- H2专用变更集 --> <changeSet id="create_table_h2" author="your-name" context="test"> <preConditions onFail="MARK_RAN"> <dbms type="h2"/> </preConditions> <sql> CREATE TABLE test_table ( id BIGINT AUTO_INCREMENT PRIMARY KEY, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) </sql> </changeSet>
不过这个方案会增加维护成本,除非特殊情况不推荐使用。
亲测前三个方法都能解决问题,优先推荐前两个,既能保持变更集的通用性又不用额外配置太多~
内容的提问来源于stack exchange,提问作者1Z10
相关产品推荐
相关产品推荐

