Java 在没有 Hibernate Annotations 的情况下为 PostgreSQL 的文本类型更正 JPA Annotation

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28588311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 06:28:47  来源:igfitidea点击:

Correct JPA Annotation for PostgreSQL's text type without Hibernate Annotations

javahibernatepostgresqljpajdbc

提问by knoe

I'm developing an application using:

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

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

And I would like to use the PostgreSQL text datatype for some String attributes. As far as I know, in JPA this should be the correct annotation, to use text in PostgreSQL:

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

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

When I annotate my entity like this, I run into errors which look like this: http://www.shredzone.de/cilla/page/299/string-lobs-on-postgresql-with-hibernate-36.html

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

In short: It seems that hibernate and jdbc go not hand in hand for clob/text-types.

简而言之:对于clob/text-types,hibernate和jdbc似乎并不一致。

The solution described is working:

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

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

But this has a significant downside: The source code needs hibernate at compile time, which should be unnecessary (That's one reason for using JPA in the first place).

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

Another way is to use the column annotation like this:

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

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

Which works nicely, BUT: Now I'm stuck with databases which have a text type (and is also called text ;) ) and if another database will be used in the future the annotations can be overlooked easily. Thus the possible error can be hard to find, because the datatype is defined in a String and therefore can not be found before runtime.

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

Is there a solution, which is so easy, I just don't see it? I'm very sure that I'm not the only one using JPA in combination with Hibernate and PostgreSQL. So I'm a little confused that I can't find more questions like this.

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

Just to complete the question, the persistence.xml looks like this:

为了完成这个问题,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>

UPDATE:

更新:

回答by Predrag Maric

I would go with simple private String description;. The column type is only a problem if you are generating the database from your code, because it will be generated as varcharinstead of text.

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

It is great to code in database agnostic way, and without any JPA vendor specific things, but there are cases where this just isn't possible. If the reality is that you will have to support multiple database types with all their specifics, then you have to account for those specifics somewhere. One option is to use columnDefinitionfor defining column type. Another is to leave the code as it is, and just change the column type in the database. I prefer the second one.

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

回答by holmis83

Since the texttype is not a part of the SQL standard there is no official JPA way I guess.

由于该text类型不是 SQL 标准的一部分,所以我猜没有官方的 JPA 方式。

However, the texttype is quite similar to varchar, but without the length limit. You can hint the JPA implementation with the lengthproperty of @Column:

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

@Column(length=10485760)
private String description;

Update:10 MiB seems to be the maximum length for varcharin postgresql. The textis almostunlimited, according the documentation:

更新:10 MiB 似乎是varcharpostgresql 中的最大长度。该text几乎无限的,根据文档

In any case, the longest possible character string that can be stored is about 1 GB.

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

回答by Torsten Krah

If you want to use plain JPA you could just remap the used CLOB type on the Dialect like this:

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

public class PGSQLMapDialect extends PostgreSQL9Dialect {


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


}

So it won't use the CLOB mapping from the JDBC driver which uses a OID for the column and stores/loads the text via large object handling. This would just result in setString and getString calls on the createt text column on the Postgres JDBC Driver via the VarcharTypeDescriptor class.

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

回答by Eliska P.

I just had to add this annotation:

我只需要添加这个注释:

@Column(columnDefinition="TEXT")

It did not work on its own. I had to recreate the table in the database.

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

DROP TABLE yourtableor just alter column type to textwith ALTER TABLEstatement

DROP TABLE yourtable或者只是将列类型更改为textwithALTER TABLE语句