我正在尝试在 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.2.5) 使用 SQL Server 2008 R2 测试了完全相同的代码(纯 UUID,没有转换 - 上面发布的代码的第一个版本)而且,你猜怎么着,它发挥了作用(当然我必须更改 persistence.xml 中与连接相关的信息)。
现在,这是 PostgreSQL 特定的问题还是什么?
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
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 字段即可。
要使其与 Hibernate 5.1.x 一起使用,您可以关注 Steve Ebersole 在此处评论
@Id
@GeneratedValue
@Column( columnDefinition = "uuid", updatable = false )
public UUID getId() {
return id;
}
新版本
>= 8.4-701
Postgresql JDBC 驱动程序正确处理 java.util.UUID
映射。 Hibernate 也是如此 >= 4.3.x
。
查看详细信息https://stackoverflow.com/a/780922/173149:
将数据库uuid类型映射到java.util.UUID。这仅适用于 相对较新的服务器 (8.3) 和 JDK (1.5) 版本。
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;
}
}
在 postgresql url 连接上添加此标志:
?stringtype=unspecified
这样
jdbc:postgresql://localhost:5432/yourdatabase?stringtype=unspecified