当项目同时使用MySQL和PostgreSQL时,从JsonStringType切换到JsonBinaryType

当项目同时使用MySQL和PostgreSQL时,从JsonStringType切换到JsonBinaryType,mysql,postgresql,hibernate,mariadb,hibernate-types,Mysql,Postgresql,Hibernate,Mariadb,Hibernate Types,当需要从PostgreSQL切换到MariaDB/MySql时,我对json列有一个问题。 我使用Spring Boot+JPA+Hibernate+Hibernate-types-52。 我要映射的表如下: CREATE TABLE atable( ... acolumn JSON, ... ); 好的,它适用于PostgreSQL和MariaDB/MySql。 问题是,当我想要部署一个可以轻松地从一个切换到另一个的应用程序时,因为PostgreSQL和MySQL/MariaDB的正


当需要从PostgreSQL切换到MariaDB/MySql时,我对json列有一个问题。
我使用Spring Boot+JPA+Hibernate+Hibernate-types-52。
我要映射的表如下:

CREATE TABLE atable(
 ...
 acolumn JSON,
 ... 
);
好的,它适用于PostgreSQL和MariaDB/MySql。
问题是,当我想要部署一个可以轻松地从一个切换到另一个的应用程序时,因为PostgreSQL和MySQL/MariaDB的正确hibernate-types-52实现是不同的

这适用于MySQL/MariaDB

@Entity
@Table(name = "atable")
@TypeDef(name = "json", typeClass = JsonStringType.class)
  public class Atable {
  ...
  @Type(type = "json")
  @Column(name = "acolumn", columnDefinition = "json")
  private JsonNode acolumn;
  ...
}
这适用于PosgreSQL

@Entity
@Table(name = "atable")
@TypeDef(name = "json", typeClass = JsonBinaryType.class)
public class Atable {
  ...
  @Type(type = "json")
  @Column(name = "acolumn", columnDefinition = "json")
  private JsonNode acolumn;
  ...
}

任何从JsonBinaryType切换到JsonStringType的解决方案(或解决此问题的任何其他解决方案)都值得赞赏。

从Hibernate Types项目的
2.11
版本开始,您只需使用
JsonType
,它可以与PostgreSQL、MySQL、Oracle、SQL Server或H2一起使用

因此,使用
JsonType
而不是
JsonBinaryType
JsonStringType

@Entity
@Table(name = "atable")
@TypeDef(name = "json", typeClass = JsonType.class)
public class Atable {

  @Type(type = "json")
  @Column(name = "acolumn", columnDefinition = "json")
  private JsonNode acolumn;

}

就这样

您可以做一些疯狂的事情,但这仅适用于特定类型和列:

首先,要用动态映射替换静态
@TypeDef

您可以使用
hibernateproperties自定义程序
添加
typecontributor列表

@Configuration
public class HibernateConfig implements HibernatePropertiesCustomizer {

  @Value("${spring.jpa.database-platform:}")
  private Class<? extends Driver> driverClass;

  @Override
  public void customize(Map<String, Object> hibernateProperties) {

    AbstractHibernateType<Object> jsonType;
    if (driverClass != null && PostgreSQL92Dialect.class.isAssignableFrom(driverClass)) {
      jsonType = new JsonBinaryType(Atable.class);
    } else {
      jsonType = new JsonStringType(Atable.class);
    }

    hibernateProperties.put(EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS,
        (TypeContributorList) () -> List.of(
            (TypeContributor) (TypeContributions typeContributions, ServiceRegistry serviceRegistry) ->
                typeContributions.contributeType(jsonType, "myType")));
  }
}
作为演示,我只检查PostgreSQL,并且只将动态列定义应用于特定实体中的特定列:

public class JsonColumnMappingIntegrator implements Integrator {

  public static final JsonColumnMappingIntegrator INSTANCE =
      new JsonColumnMappingIntegrator();

  @Override
  public void integrate(
      Metadata metadata,
      SessionFactoryImplementor sessionFactory,
      SessionFactoryServiceRegistry serviceRegistry) {

    Database database = metadata.getDatabase();

    if (PostgreSQL92Dialect.class.isAssignableFrom(database.getDialect().getClass())) {
      Column acolumn=
        ((Column) metadata.getEntityBinding(Atable.class.getName()).getProperty("acolumn").getColumnIterator().next());
      settingsCol.setSqlType("json");
    }
  }

  @Override
  public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
  }
}
metadata.getEntityBindings()
将为您提供所有实体绑定,您可以在这些绑定上迭代,然后再迭代属性。但这似乎效率很低。
我也不确定是否可以设置诸如“IS JSON”约束等,因此自定义创建脚本会更好。

从avalue更改为acolumn…好的,似乎反序列化有问题。。。查看itRight,因此不会调用
setParameters
方法。TypeContributors似乎不支持参数化类型:可以用具体类型实例化Json*类型。这意味着您必须为要使用的每个(基本)类创建一个自定义类型…请查看我的更新答案。事实上,你可以删除你的评论,因为它不再相关。
public class JsonColumnMappingIntegrator implements Integrator {

  public static final JsonColumnMappingIntegrator INSTANCE =
      new JsonColumnMappingIntegrator();

  @Override
  public void integrate(
      Metadata metadata,
      SessionFactoryImplementor sessionFactory,
      SessionFactoryServiceRegistry serviceRegistry) {

    Database database = metadata.getDatabase();

    if (PostgreSQL92Dialect.class.isAssignableFrom(database.getDialect().getClass())) {
      Column acolumn=
        ((Column) metadata.getEntityBinding(Atable.class.getName()).getProperty("acolumn").getColumnIterator().next());
      settingsCol.setSqlType("json");
    }
  }

  @Override
  public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
  }
}