使用H2数据库在play slick中运行测试时,未知数据类型为“ JSONB”

Azi*_*zik 5 postgresql scala h2 playframework slick

我在使用Playframework中运行测试时遇到 进化问题未知数据类型:“ JSONB”

  • 适用于Scala的playframework v2.6.6
  • 畅玩v3.0.2
  • play-slick-evolutions v3.0.2
  • PostgreSQL-42.0.0
  • h2database-1.4.194

我的H2DbConnector看起来像这样:

import entities.StubData._
import org.scalatest.{BeforeAndAfterAll, FunSuite}
import play.api.db.DBApi
import play.api.db.evolutions.Evolutions
import play.api.inject.guice.GuiceApplicationBuilder

trait H2DbConnector extends FunSuite with BeforeAndAfterAll {
  val appBuilder = new GuiceApplicationBuilder()
    .configure(configuration)

  val injector = appBuilder.injector
  lazy val databaseApi = injector.instanceOf[DBApi]

  override def beforeAll() = {
    Evolutions.applyEvolutions(databaseApi.database("default"))
  }

  override def afterAll() = {
    Evolutions.cleanupEvolutions(databaseApi.database("default"))
  }
}
Run Code Online (Sandbox Code Playgroud)

在application.test.conf中

slick.dbs.default.driver = "slick.driver.H2Driver$"
slick.dbs.default.db.driver = "org.h2.Driver"
slick.dbs.default.db.url = "jdbc:h2:mem:play;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE"
Run Code Online (Sandbox Code Playgroud)

我在Evolutions 2.sql文件中有一条问题线

ALTER TABLE "Messages" ADD COLUMN "metaJson" JSONB NULL;
Run Code Online (Sandbox Code Playgroud)

当我运行dao测试时出现如下错误

2017-12-21 16:08:40,409 [error] p.a.d.e.DefaultEvolutionsApi - Unknown data type: "JSONB"; SQL statement:
ALTER TABLE "Messages" ADD COLUMN "metaJson" JSONB NULL [50004-194] [ERROR:50004, SQLSTATE:HY004]
[info] OptoutsDaoTest *** ABORTED ***
[info]   play.api.db.evolutions.InconsistentDatabase: Database 'default' is in an inconsistent state![An evolution has not been applied properly. Please check the problem and resolve it manually before marking it as resolved.]
[info]   at play.api.db.evolutions.DatabaseEvolutions.$anonfun$checkEvolutionsState$3(EvolutionsApi.scala:285)
[info]   at play.api.db.evolutions.DatabaseEvolutions.$anonfun$checkEvolutionsState$3$adapted(EvolutionsApi.scala:270)
[info]   at play.api.db.evolutions.DatabaseEvolutions.executeQuery(EvolutionsApi.scala:317)
[info]   at play.api.db.evolutions.DatabaseEvolutions.checkEvolutionsState(EvolutionsApi.scala:270)
[info]   at play.api.db.evolutions.DatabaseEvolutions.evolve(EvolutionsApi.scala:239)
[info]   at play.api.db.evolutions.Evolutions$.applyEvolutions(Evolutions.scala:193)
[info]   at H2DbConnector.beforeAll(H2DbConnector.scala:15)
[info]   at H2DbConnector.beforeAll$(H2DbConnector.scala:14)
[info]   at OptoutsDaoTest.beforeAll(OptoutsDaoTest.scala:5)
[info]   at org.scalatest.BeforeAndAfterAll.liftedTree1$1(BeforeAndAfterAll.scala:212)
[info]   ...
Run Code Online (Sandbox Code Playgroud)

您能帮我解决这个问题吗?

whi*_*rue 12

我最近在JSONB 和 H2 上也遇到了这个问题。我通过创建 JSONB 到 JSON 的别名解决了这个问题,并让它仅在 H2 的测试配置文件期间运行。

CREATE TYPE "JSONB" AS json; 
Run Code Online (Sandbox Code Playgroud)

它不是 JSONB,但 JSONB 与 JSON 的区别(至少在 postgres 中)本质上是读取性能,这对于测试目的来说并不重要(这么多)。

也许这个例子也有帮助:

这是一个使用flyway的例子。创建 sql 条目以在 /resources/db/tests 上创建仅在测试配置文件上运行的 jsonb 的别名类型。

我们使用的是 spring,所以这里是application.yml的入口:

spring:
  profiles: mytest
  datasource:
    continueOnError: false
    url: jdbc:h2:mem:myapp-db;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE
flyway:
   enabled: true
   locations: classpath:db/migration, classpath:db/tests
  [......]
Run Code Online (Sandbox Code Playgroud)

这是 ${project.dir}/resources/db/ 的列表

在此处输入图片说明

这是魔法:

在文件的内容中,我创建了一个名为 JSONB 的类型,它基本上是 JSON 类型的别名。注意:据我所知,大写是必要的(特别是当您在创建表时引用它时),因为 H2 似乎会自动将类型名称更改为大写:

CREATE TYPE "JSONB" AS json; 
Run Code Online (Sandbox Code Playgroud)

以下是使用此类型创建表的示例:

CREATE TABLE "XXX" (
    id BIGSERIAL PRIMARY KEY,
    my_json_column_name JSONB NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

在 hibernate 方面,我使用 hibernate-types52 中的 JsonBinaryType 类型在此链接上查看更多信息。

@Data
@TypeDef(name = "jsonb", typeClass = com.vladmihalcea.hibernate.type.json.JsonBinaryType.class)
@Entity(name = "XXX")
@Table(name = "XXX")
public class XXX {

  @Type(type = "jsonb")
  @Column(name = "my_json_column_name", nullable = false)
  private String myJsonColumnName;

  //OR

  @Type(type = "jsonb")
  @Column(name = "my_json_column_name", nullable = false)
  private List<MYCustomTypeThatMatchesJsonObject> myJsonColumnName;

}
Run Code Online (Sandbox Code Playgroud)

我希望它可以帮助某人。它对我有用。


2020-07-13 更新

我停止在我的项目中使用 H2 并开始使用testcontainers。非常容易设置,您可以在真实的数据库环境中进行测试。

  • 我想强调考虑使用测试容器的建议。 (2认同)

pam*_*amu 5

H2 不支持JSONB列类型。

所有支持的列类型支持的 H2 数据类型

尝试在测试中也使用 postgres 或编写两个数据库都能理解的标准 SQL 语句。