如今在开发系统时,有各种各样的数据库供我们选择。之前我们在博客基于MariaDB4j实现持久层单元测试介绍了使用MariaD4j代替作为MySQL的替身执行单元测试,但是并不是所有的数据库都能找到合适的替身来执行单元测试。
今天作者在写测试的过程中就遇到了一个这样的问题。我们使用的数据库是PostgreSQL,Migration框架是Liquibase,单元测试过程中使用的数据库是H2,并且数据表中用到了PostgreSQL的扩展类型JSONB。在执行测试过程时,报了未知数据类型异常:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.LiquibaseException: liquibase.exception.MigrationFailedException: Migration failed for change set liquibase/db.changelog-20230506.xml::modify_column_data_type::developer:
Reason: liquibase.exception.DatabaseException: Unknown data type: "JSONB"; SQL statement:
映入脑中的第一个想法是重新写一套schema,并用这套schema初始化H2数据库,但这种方法会带来:
- 额外的工作量
- 每次修改schema都要同时修改两个地方
是否有更简单的办法来解决这个问题?我们知道H2支持很多中类型1
而JSONB和JSON两中类型非常相似(主要差别在存储格式和搜索性能上),能否通过为JSON定义一个JSONB的别名。于是通过搜索相关的SQL语法,果然找到了如下SQL语法2:
CREATE TYPE metric_meter AS DOUBLE;
CREATE TYPE imperial_foot AS DOUBLE;
结合H2在建立链接是可以执行一下SQL语句3,瞬间让我找到了解决方法。
String url = "jdbc:h2:mem:test;INIT=runscript from '~/create.sql'\\;runscript from '~/init.sql'";
说了这么多,让我总结一下最终的解决方案吧!
首先:创建一个H2数据库的初始脚本init.sql(笔者是放在spring boot工程的test/resources目录下)。
#CREATE TYPE "JSONB" AS json;
然后:更改数据源链接配置(application-test.yml)。
spring:
datasource:
url: jdbc:h2:mem:test;INIT=runscript from 'classpath:init.sql'
username: sa
password: password
driver-class-name: org.h2.Driver
jpa:
database-platform: org.hibernate.dialect.PostgreSQL95Dialect
有了【别名大法】,是不是以后就可以用H2作为很多关系型数据库的替身了,毕竟H2提供了几乎我们常用的所有数据类型。
H2 DataTypes ↩︎
SQL Standard User Defined Types and Routines ↩︎
execute_sql_on_connection ↩︎