Сохранение 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 или что?
Ответы
Ответ 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.