Подтвердить что ты не робот

Правильная JPA-аннотация для текстового типа PostgreSQL без аннотаций Hibernate

Я разрабатываю приложение, используя:

  • 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.

Описанное решение работает:

@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;
    ...
}

Что работает красиво, НО: Теперь я застрял с базами данных, которые имеют текстовый тип (и также называется text;)), и если в будущем будет использоваться другая база данных, аннотации можно легко пропустить. Таким образом, возможная ошибка может быть трудно найти, потому что тип данных определяется в 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>

ОБНОВЛЕНИЕ:

4b9b3361

Ответ 1

Так как тип text не является частью стандарта SQL, то я не предполагаю официального JPA-метода.

Однако тип text очень похож на varchar, но без ограничения длины. Вы можете намекнуть на реализацию JPA с помощью свойства length @Column:

@Column(length=10485760)
private String description;

Обновление: 10 MiB кажется максимальной длиной для varchar в postgresql. text почти неограничен, согласно документации:

В любом случае, самая длинная строка символов, которая может быть сохранена составляет около 1 ГБ.

Ответ 2

Я бы пошел с простым private String description;. Тип столбца является только проблемой, если вы генерируете базу данных из своего кода, потому что она будет сгенерирована как varchar вместо text.

Это здорово кодировать в агностическом режиме базы данных и без каких-либо специфических особенностей поставщика JPA, но бывают случаи, когда это просто невозможно. Если реальность такова, что вам придется поддерживать несколько типов баз данных со всей их спецификой, тогда вам нужно учитывать эти особенности. Один из вариантов - использовать columnDefinition для определения типа столбца. Другой - оставить код таким, какой он есть, и просто изменить тип столбца в базе данных. Я предпочитаю второй.

Ответ 3

Если вы хотите использовать простой 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);
  }


}

Таким образом, он не будет использовать сопоставление CLOB из драйвера JDBC, который использует OID для столбца и сохраняет/загружает текст с помощью обработки больших объектов. Это просто приведет к вызовам setString и getString в столбце текста createt в драйвере JDBC Postgres через класс VarcharTypeDescriptor.