如何将 CLOB 与 Hibernate 以及 Postgres 和 H2 一起使用

Posted

技术标签:

【中文标题】如何将 CLOB 与 Hibernate 以及 Postgres 和 H2 一起使用【英文标题】:How to use CLOB with Hibernate and both Postgres and H2 【发布时间】:2020-05-27 14:10:08 【问题描述】:

我正在尝试将一个长文本文件存储到 DBMS 中。这是我的表定义:

@Entity
@Table(name = "foos")
public class Foo 
    private static final long serialVersionUID = 7111245814238004034L;
    @Id
    @GeneratedValue
    @Column(nullable = false, name = "id")
    private long id;

    @Lob
    @Column(nullable = false, name = "content", length = 100_000)
    private String content;

    public long getId() 
        return id;
    

    public String getContent() 
        return content;
    

这是我的 liquibase 变更集:

    <createTable tableName="foos">
        <column name="id" type="bigint" />
        <column name="content" type="clob" />
    </createTable>

这适用于 H2,但对于 Postgres,当我尝试加载 Foo 时,我得到:

org.postgresql.util.PSQLException: Bad value for type long : <content>
    org.postgresql.jdbc.PgResultSet.toLong(PgResultSet.java:2876)
    org.postgresql.jdbc.PgResultSet.getLong(PgResultSet.java:2083)
    org.postgresql.jdbc.PgResultSet.getClob(PgResultSet.java:452)
    org.postgresql.jdbc.PgResultSet.getClob(PgResultSet.java:439)
    org.apache.commons.dbcp2.DelegatingResultSet.getClob(DelegatingResultSet.java:675)
    org.apache.commons.dbcp2.DelegatingResultSet.getClob(DelegatingResultSet.java:675)
    org.hibernate.type.descriptor.sql.ClobTypeDescriptor$1.doExtract(ClobTypeDescriptor.java:44)
    org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)
    org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257)
    org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)
    org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243)

(不过,将 Foo 保存到数据库中是可行的)。

如果我尝试向content 添加另一个注释:

@Type(type = "org.hibernate.type.TextType")

这适用于 Postgres(产品环境)但不适用于 H2(测试环境):

Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [content] in table [public.war_contexts]; found [clob (Types#CLOB)], but expecting [varchar(2147483647) (Types#LONGVARCHAR)]
    at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateColumnType(AbstractSchemaValidator.java:159)
    at org.hibernate.tool.schema.internal.AbstractSchemaValidator.validateTable(AbstractSchemaValidator.java:143)
    at org.hibernate.tool.schema.internal.GroupedSchemaValidatorImpl.validateTables(GroupedSchemaValidatorImpl.java:42)
    at org.hibernate.tool.schema.internal.AbstractSchemaValidator.performValidation(AbstractSchemaValidator.java:89)
    at org.hibernate.tool.schema.internal.AbstractSchemaValidator.doValidation(AbstractSchemaValidator.java:68)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:192)
    at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:73)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:314)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:468)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1237)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:391)
    ... 81 more

关于如何在两个 DBMS 上解决问题的任何想法(如果它与 MariaDB 或 Oracle 一起使用,则可以加分)

编辑:

尝试了那些连接设置

jdbc:h2:mem:myDb;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1

但这没有帮助

【问题讨论】:

其实PostgreSQL里没有标准的CLOB数据类型。 H2支持这种数据类型,但是H2中的TEXT也映射到CLOB。 Hibernate 模式验证经常抱怨不同但仍然兼容的数据类型;如果您真的想使用不同的数据库,则需要禁用它,通常使用不同的数据库系统进行测试和生产是一个坏主意。 测试呢?当我运行我的测试时,我得到了完全相同的错误 我在使用 Postgres 和 H2 时遇到了同样的问题。使用来自this answer 的@Column(columnDefinition = "clob") 解决了它。 【参考方案1】:

使用@Column(columnDefinition = "text") 注释您的字段,如下所示:

    @Lob
    @Column(columnDefinition = "text")
    private String content;

然后确保你的列类型等于 SQL text 类型!

我的 Spring 数据源配置如下:

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password: sa
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect

我对其进行了测试,它适用于 Postgres 和 H2。

【讨论】:

以上是关于如何将 CLOB 与 Hibernate 以及 Postgres 和 H2 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate向数据库存入BLOB和CLOB类型的数据

Struts+Spring+Hibernate处理Lob(Blob,Clob)

hibernate操作大文本字段Blob和Clob

Struts+Spring+Hibernate处理Lob(Blob,Clob)

Hibernate or JPA Annotation中BLOBCLOB注解写法

将 BLOB/CLOB 作为参数传递给 PL/SQL 函数