如何让jsonb ColumnTransformer兼容H2数据库以实现测试切换
PostgreSQL jsonb 兼容H2数据库测试方案
问题背景
后端基于PostgreSQL数据库开发,实体类通过jsonb类型存储Map结构数据,搭配@ColumnTransformer实现写入转换逻辑,但在H2数据库执行测试时,触发Unknown data type: "JSONB"报错。
实体类代码
@JsonProperty("home_address") @Column(name = "home_address", nullable = true, columnDefinition = "jsonb") @ColumnTransformer(write = "?::jsonb") @Convert(converter = JsonbConverter.class) private Map<String, Object> homeAddress;
报错信息
address jsonb, )" via JDBC [Unknown data type: "JSONB";] at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:94) at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:233) at org.hibernate.tool.schema.internal.Helper.applySqlStrings(Helper.java:217) at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createTables(SchemaCreatorImpl.java:428) at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createSequencesTablesConstraints(SchemaCreatorImpl.java:344) at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:239) at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:172) at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:142) at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:118) at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:250) at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$5(SchemaManagementToolCoordinator.java:144) at java.base/java.util.HashMap.forEach(HashMap.java:1429)
解决方案
1. 配置H2为PostgreSQL兼容模式
修改H2数据库连接URL,添加兼容参数,让H2模拟PostgreSQL的类型解析逻辑:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1
添加MODE=PostgreSQL后,H2会自动将jsonb识别为JSON类型的别名,直接解决类型未知报错。
2. 优化实体类注解适配双数据库
方案A:使用Hibernate Types库自动适配
引入hibernate-types依赖(根据Hibernate版本选择对应artifactId,如Hibernate 5.x用hibernate-types-52),修改实体类注解:
@JsonProperty("home_address") @Column(name = "home_address", nullable = true) @Type(type = "com.vladmihalcea.hibernate.type.json.JsonBinaryType") private Map<String, Object> homeAddress;
该类型处理器会自动适配数据库:PostgreSQL环境用jsonb,H2环境用原生JSON类型,无需手动配置columnDefinition和ColumnTransformer。
方案B:条件化配置注解(无额外依赖)
通过Spring Profile区分测试与生产环境,实现注解动态切换:
- 生产环境(PostgreSQL)保留原注解;
- 测试环境(H2)替换类型定义与转换逻辑:
@JsonProperty("home_address") @Column(name = "home_address", nullable = true, columnDefinition = "${db.json.type:jsonb}") @ColumnTransformer(write = "${db.json.transform:?::jsonb}") @Convert(converter = JsonbConverter.class) private Map<String, Object> homeAddress;
测试配置文件中添加参数:
db.json.type=json db.json.transform=CAST(? AS JSON)
3. 初始化H2时注册jsonb类型
若不想修改连接URL或实体类,可在H2初始化阶段执行SQL注册jsonb类型:
创建初始化脚本src/test/resources/h2-init.sql:
CREATE TYPE JSONB AS JSON;
测试配置中指定脚本位置:
spring.sql.init.data-locations=classpath:h2-init.sql
验证
启动测试后,检查H2数据库表结构是否正常创建,同时验证JSON数据的读写逻辑,确保在PostgreSQL和H2环境中都能正确序列化、反序列化。
内容的提问来源于stack exchange,提问作者user352290
相关产品推荐
相关产品推荐

