Java PostgreSQL的正确JPA注释';不带Hibernate注释的文本类型

Java PostgreSQL的正确JPA注释';不带Hibernate注释的文本类型,java,hibernate,postgresql,jpa,jdbc,Java,Hibernate,Postgresql,Jpa,Jdbc,我正在使用以下工具开发应用程序: Java 1.7 JPA(包含在JavaEEAPI7.0中) Hibernate 4.3.8.1最终版本 PostgreSQL JDBC 9.4-1200-jdbc41 PostgreSQL 9.3.6 我想对一些字符串属性使用PostgreSQL文本数据类型。据我所知,在JPA中,要使用PostgreSQL中的文本,这应该是正确的注释: @Entity public class Product{ ... @Lob private S

我正在使用以下工具开发应用程序:

  • Java 1.7
  • JPA(包含在JavaEEAPI7.0中)
  • Hibernate 4.3.8.1最终版本
  • PostgreSQL JDBC 9.4-1200-jdbc41
  • PostgreSQL 9.3.6
我想对一些字符串属性使用PostgreSQL文本数据类型。据我所知,在JPA中,要使用PostgreSQL中的文本,这应该是正确的注释:

@Entity
public class Product{
    ...
    @Lob
    private String description;
    ....
}
当我像这样注释实体时,我会遇到如下错误:

简而言之:对于clob/文本类型,hibernate和jdbc似乎并不是齐头并进的

所述解决方案正在发挥作用:

@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;
    ...
}
<?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>
public class PGSQLMapDialect extends PostgreSQL9Dialect {


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


}
这很有效,但是: 现在我一直在使用文本类型(也称为text;)的数据库,如果将来使用另一个数据库,那么注释很容易被忽略。因此,很难找到可能的错误,因为数据类型是在字符串中定义的,因此在运行时之前无法找到

有没有一个解决办法,这么简单,我就是看不出来?我非常肯定,我不是唯一一个将JPA与Hibernate和PostgreSQL结合使用的人。所以我有点困惑,我找不到更多像这样的问题

为了完成这个问题,persistence.xml如下所示:

@Entity
public class Product{
    ...
    @Column(columnDefinition = "text")
    private String description;
    ...
}
<?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>
public class PGSQLMapDialect extends PostgreSQL9Dialect {


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


}

org.hibernate.ejb.HibernatePersistence
com.app.model.Product
更新:

  • 这个问题或多或少与这个问题相当,选择的答案是这个问题中描述的第二种方法,我不喜欢这种方法,因为hibernate运行时依赖性:

  • 这似乎与:


    • 我会选择简单的
      私有字符串描述。只有当您从代码生成数据库时,列类型才是一个问题,因为它将作为
      varchar
      而不是
      text
      生成


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

      因为
      文本类型不是SQL标准的一部分,所以我想没有正式的JPA方式

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

      @列(长度=10485760)
      私有字符串描述;
      
      更新:10 MiB似乎是postgresql中
      varchar
      的最大长度。根据以下说明,
      文本
      几乎是无限的:

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


      如果您想使用普通JPA,只需在方言上重新映射使用过的CLOB类型,如下所示:

      @Entity
      public class Product{
          ...
          @Column(columnDefinition = "text")
          private String description;
          ...
      }
      
      <?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>
      
      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映射,JDBC驱动程序使用OID作为列并通过大对象处理存储/加载文本。
      这只会导致通过VarcharTypeDescriptor类对Postgres JDBC驱动程序上的createt text列调用setString和getString。

      我只需添加以下注释:

      @Column(columnDefinition="TEXT")
      
      它本身不起作用。我必须在数据库中重新创建表


      DROP TABLE yourtable
      或使用
      alter TABLE
      语句将列类型更改为
      text
      ,因为您讨论的是真正的部署问题(自动生成的DDL),您不能在Postgres中手动将表创建为文本,而不在类中指定任何内容吗,我希望能够从hibernate生成DB。@chrylis当你这样说的时候,听起来是错误的:D我更喜欢的方式是我用JPA的方式使用注释(简单地说就是
      @Lob
      )。让hibernate/jdbc在后台发挥神奇的作用。正如我所知,
      @Lob字符串
      应该在DB2、Oracle中产生
      clob
      ,在H2/HSQLDB中产生
      longvarchar
      ,在MySQL中产生
      longtext
      text
      ,在PostgreSQL中产生
      text
      。我的问题是,hibernate和postgresql jdbc创建了一个错误,这里不应该有任何问题。但是文本和lob在语义上不是一回事。我在寻找你想要的相反的东西,你的问题就是我的答案。好奇。我刚刚添加了
      列definition=“text”
      。谢谢。是的,我想从代码生成DB。如果我不需要的话。我发现,@Column(columnDefinition=“longvarchar”)私有字符串描述;这样可以很好地工作,因为hibernate/jdbc驱动程序组合需要文本而不是clob地址。这就是链接的长/文本错误的问题所在。但是表创建将失败,因为postgresql不知道longvarchar类型。如果我能自己在PostgreSQL中定义一个像longvarchar=text这样的别名,这可能会很有趣……这或多或少与您的解决方案相同,因为columnDefiniton只在表定义中使用。@knoe:Postgres中的
      varchar
      text
      之间绝对没有区别。@a_horse_没有名称是对的,但是为没有注释的字符串生成的列是varchar(255),但我不想限制它,这是第一页中的问题