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

Сохранение UUID в PostgreSQL с использованием JPA

Я пытаюсь сохранить объект в PostgreSQL, который использует UUID в качестве первичного ключа. Я попытался сохранить его как обычный UUID:

@Id
@Column(name = "customer_id")
private UUID id;

С приведенным выше я получаю эту ошибку:

ERROR: column "customer_id" is of type uuid but expression is of type bytea
Hint: You will need to rewrite or cast the expression.
Position: 137

Я также попытался сохранить UUID как байт [] безрезультатно:

@Transient
private UUID id;

@Id
@Column(name = "customer_id")
@Access(AccessType.PROPERTY)
@Lob
protected byte[] getRowId() {
    return id.toString().getBytes();
}

protected void setRowId(byte[] rowId) {
    id = UUID.fromString(new String(rowId));
}

Если я удалю @Lob, ошибка, которую я получаю, такая же, как и выше. Но при применении @Lob ошибка немного меняется:

ERROR: column "customer_id" is of type uuid but expression is of type bigint
Hint: You will need to rewrite or cast the expression.
Position: 137

Мне очень плохо, что я не могу сделать что-то простое, как это!

Я использую Hibernate 4.1.3.Final с PostgreSQL 9.1.

Я видел многочисленные вопросы о SO более или менее с одной и той же проблемой, но они все старые, и никто, кажется, не имеет прямого ответа.

Я хотел бы добиться этого стандартным способом, не прибегая к уродливым хакам. Но если это может быть достигнуто только, хотя (уродливые) хаки, возможно, это то, что я сделаю. Тем не менее, я не хочу хранить UUID в качестве varchar в базе данных, поскольку это не подходит для производительности. Кроме того, я хотел бы не вводить зависимость Hibernate в моем коде, если это возможно.

Любая помощь будет принята с благодарностью.

ОБНОВЛЕНИЕ 1 (2012-07-03 12:15)

Ну, ну, ну... Интересно, что я тестировал тот же самый код (простой UUID, без преобразования - первая версия кода, вышеописанного) с SQL Server 2008 R2 с использованием драйвера JTDS (v1. 2.5), и, угадайте, что это работало как прелесть (конечно, мне пришлось изменить информацию, связанную с подключением, в файле persistence.xml).

Теперь, это проблема с PostgreSQL или что?

4b9b3361

Ответ 1

Драйвер PostgreSQL JDBC выбрал, к сожалению, способ представления нестандартных кодов типа JDBC. Они просто отображают все их в Types.OTHER. Короче говоря, вам нужно включить специальное сопоставление типов Hibernate для обработки сопоставлений UUID (для столбцов типа данных uuid, специфичных для postgres):

@Id
@Column(name = "customer_id")
@org.hibernate.annotations.Type(type="org.hibernate.type.PostgresUUIDType")
private UUID id;

или более лаконично:

@Id
@Column(name = "customer_id")
@org.hibernate.annotations.Type(type="pg-uuid")
private UUID id;

Другой (лучший) вариант - зарегистрировать org.hibernate.type.PostgresUUIDType как сопоставление типа Hibernate по умолчанию для всех атрибутов, выставленных как java.util.UUID. Это описано в документации @http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch06.html#types-registry

Ответ 2

JPA 2.1 предоставляет очень простой способ использования типа столбца uuid PostgreSQL и java.util.UUID в качестве типа соответствующего поля объекта:

@javax.persistence.Converter(autoApply = true)
public class PostgresUuidConverter implements AttributeConverter<UUID, UUID> {

    @Override
    public UUID convertToDatabaseColumn(UUID attribute) {
        return attribute;
    }

    @Override
    public UUID convertToEntityAttribute(UUID dbData) {
        return dbData;
    }

}

Просто добавьте этот класс в свою конфигурацию персистентности и отметьте поля UUID с помощью @Column(columnDefinition="uuid").

Ответ 3

Чтобы работать с Hibernate 5.1.x, вы можете следовать за Стивом Эберсолем здесь

@Id
@GeneratedValue
@Column( columnDefinition = "uuid", updatable = false )
public UUID getId() {
    return id;
}

Ответ 4

Более новая версия >= 8.4-701 драйвера Postgresql JDBC корректно обрабатывает отображение java.util.UUID. И так же Hibernate >= 4.3.x.

Подробнее о fooobar.com/questions/236192/...:

Map the database uuid type to java.util.UUID.
This only works for relatively new server (8.3) and JDK (1.5) versions.

Ответ 5

Решение, предложенное Олегом, не сработало отлично для меня (это не удалось, если вы пытались сохранить нулевое значение). Ниже приведено исправленное решение, которое также работает с нулевыми значениями.

В моем случае я использую EclipseLink, хотя, если вы используете Hibernate, вам может это не понадобиться.

public class UuidConverter implements AttributeConverter<UUID, Object> {
    @Override
    public Object convertToDatabaseColumn(UUID uuid) {
        PGobject object = new PGobject();
        object.setType("uuid");
        try {
            if (uuid == null) {
                object.setValue(null);
            } else {
                object.setValue(uuid.toString());
            }
        } catch (SQLException e) {
            throw new IllegalArgumentException("Error when creating Postgres uuid", e);
        }
        return object;
    }

    @Override
    public UUID convertToEntityAttribute(Object dbData) {
        return (UUID) dbData;
    }
}

Ответ 6

Добавляет этот флаг к сообщению postgresql url:? stringtype = неуказанный

нравится

JDBC: PostgreSQL://локальный: 5432/yourdatabase StringType = неопределенные

Ответ 7

Я уверен, что как только вы сгенерировали UUID для записи, он будет статичным. Таким образом, нет смысла отображать UUID в качестве объекта в базу данных и затем преобразовывать его обратно в String для извлечения.

Использовать UUID как строку:

@Id
@Column(name = "customer_id")
private String id;

//getter and setter

public void setId(UUID id) {
    this.id = id.toString();
}

Также есть несколько вещей, которые следует учитывать:

  • Использовать ли ID, UUID или и то, и другое. Существует быстрое обсуждение этого.
  • Использование "uuid" для имен, а не "id", вводит в заблуждение.
  • Удаление знаков "-" из UUID, сохранение 4 байта.
  • Создание UUID в разделе @PrePersist, если вы используете Spring.