我正在尝试在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作为byte []保持无效:
@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 pm)
嗯,好吧,好吧......我使用JTDS驱动程序(v1,使用SQL Server 2008 R2)测试了完全相同的代码(普通UUID,没有转换 - 上面发布的代码的第一个版本),这很有趣。 2.5)并且,猜猜看,它作为一个魅力(当然我必须在persistence.xml中更改与连接相关的信息)。
现在,它是PostgreSQL特有的问题还是什么?
答案 0 :(得分:33)
PostgreSQL JDBC驱动程序选择了一种不幸的方式来表示非JDBC标准类型代码。他们只是将所有这些映射到Types.OTHER。简而言之,您需要启用一个特殊的Hibernate类型映射来处理UUID映射(对于postgres特定的uuid数据类型的列):
@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注册为作为java.util.UUID公开的所有属性的默认Hibernate类型映射。文档@ http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch06.html#types-registry
中对此进行了介绍答案 1 :(得分:16)
JPA 2.1提供了一种使用PostgreSQL uuid列类型和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;
}
}
只需将此类添加到持久性配置中,并使用@Column(columnDefinition="uuid")
注释UUID字段。
答案 2 :(得分:7)
要使用Hibernate 5.1.x,您可以关注Steve Ebersole comment here
@Id
@GeneratedValue
@Column( columnDefinition = "uuid", updatable = false )
public UUID getId() {
return id;
}
答案 3 :(得分:2)
Postgresql JDBC驱动程序的较新版本>= 8.4-701
正确处理java.util.UUID
映射。 Hibernate >= 4.3.x
也是如此。
详情请见https://stackoverflow.com/a/780922/173149:
Map the database uuid type to java.util.UUID.
This only works for relatively new server (8.3) and JDK (1.5) versions.
答案 4 :(得分:1)
Oleg建议的解决方案对我来说并不完美(如果你试图保持空值,则失败)。这是一个经过调整的解决方案,也适用于空值。
在我的情况下,我正在使用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;
}
}
答案 5 :(得分:0)
在postgresql url连接上添加此标志:?stringtype = unspecified
像那样JDBC:在PostgreSQL://本地主机:5432 / yourdatabase stringtype =未指定的
答案 6 :(得分:-4)
我确信,一旦为记录生成了UUID,它就会是静态的。因此,将UUID作为对象映射到数据库然后在检索时将其转换回String是没有意义的。
将UUID用作字符串:
@Id
@Column(name = "customer_id")
private String id;
//getter and setter
public void setId(UUID id) {
this.id = id.toString();
}
还有一些事情需要考虑: