在没有Hibernate Annotations的情况下纠正PostgreSQL文本类型的JPA注释

时间:2015-02-18 16:14:24

标签: java hibernate postgresql jpa jdbc

我正在使用以下方式开发应用程序:

  • Java 1.7
  • JPA(包含在javaee-api 7.0中)
  • Hibernate 4.3.8.Final
  • PostgreSQL-JDBC 9.4-1200-jdbc41
  • PostgreSQL 9.3.6

我想将PostgreSQL文本数据类型用于某些String属性。据我所知,在JPA中,这应该是正确的注释,在PostgreSQL中使用文本:

@Entity
public class Product{
    ...
    @Lob
    private String description;
    ....
}

当我像这样注释我的实体时,我会遇到如下错误: http://www.shredzone.de/cilla/page/299/string-lobs-on-postgresql-with-hibernate-36.html

简而言之:似乎hibernate和jdbc并不是clob / text-types。

所描述的解决方案正在起作用:

@Entity
public class Product{
    ...
    @Lob
    @Type(type = "org.hibernate.type.TextType")
    private String description;
    ...
}

但这有一个明显的缺点:源代码在编译时需要休眠,这应该是不必要的(这是首先使用JPA的一个原因)。

另一种方法是使用这样的列注释:

@Entity
public class Product{
    ...
    @Column(columnDefinition = "text")
    private String description;
    ...
}

哪个很好用,但是: 现在我坚持使用具有文本类型的数据库(也称为文本;))如果将来使用另一个数据库,注释很容易被忽略。因此,可能很难找到可能的错误,因为数据类型是在String中定义的,因此在运行时之前无法找到。

有没有解决方案,这很容易,我只是看不到它?我非常确定我不是唯一一个将JPA与Hibernate和PostgreSQL结合使用的人。所以我有点困惑,我无法找到更多这样的问题。

只是为了完成这个问题,persistence.xml看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
  xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                        http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="entityManager">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.app.model.Product</class>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
      <property name="javax.persistence.jdbc.url"
        value="jdbc:postgresql://localhost:5432/awesomedb" />
      <property name="javax.persistence.jdbc.user" value="usr" />
      <property name="javax.persistence.jdbc.password" value="pwd" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
      <property name="hibernate.jdbc.use_streams_for_binary" value="false" />
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />
      <property name="show_sql" value="true" />
    </properties>
  </persistence-unit>
</persistence>

更新:

4 个答案:

答案 0 :(得分:6)

由于text类型不是SQL标准的一部分,因此我认为没有正式的JPA方式。

但是,text类型与varchar非常相似,但没有长度限制。您可以使用length的{​​{1}}属性提示JPA实现:

@Column

更新: 10 MiB似乎是postgresql中@Column(length=10485760) private String description; 的最大长度。根据{{​​3}}:

varchar 几乎无限制
  

在任何情况下,可以存储的最长字符串   约为1 GB。

答案 1 :(得分:3)

如果你想使用普通的JPA,你可以像这样在dialect上重新映射使用过的CLOB类型:

public class PGSQLMapDialect extends PostgreSQL9Dialect {


  @Override
  public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
    if (Types.CLOB == sqlTypeDescriptor.getSqlType()) {
      return LongVarcharTypeDescriptor.INSTANCE;
    }
    return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
  }


}

因此它不会使用JDBC驱动程序中的CLOB映射,该驱动程序使用OID作为列并通过大对象处理存储/加载文本。 这只会通过VarcharTypeDescriptor类在Postgres JDBC驱动程序的createt文本列上调用setString和getString。

答案 2 :(得分:1)

我会选择简单的private String description;。如果从代码生成数据库,则列类型只是一个问题,因为它将生成为varchar而不是text

以数据库无关的方式进行编码是很棒的,并且没有任何JPA供应商特定的东西,但有些情况下这是不可能的。如果现实是您必须支持多种数据库类型及其所有细节,那么您必须在某处考虑这些细节。一种选择是使用columnDefinition来定义列类型。另一种方法是保持代码不变,只需更改数据库中的列类型即可。我更喜欢第二个。

答案 3 :(得分:1)

我只需要添加以下注释:

@Column(columnDefinition="TEXT")

它不能单独工作。我不得不在数据库中重新创建表。

DROP TABLE yourtable或仅使用text语句将列类型更改为ALTER TABLE