使用 JPA 在 PostgreSQL 中持久化 UUID

2022-09-01 09:21:12

我试图在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 下午)

嗯,嗯,嗯...有趣的是,我使用JTDS驱动程序(v1.2.5)在SQL Server 2008 R2上测试了完全相同的代码(普通的UUID,无转换 - 上面发布的代码的第一个版本),并且,猜猜看,它作为一个魅力(当然,我不得不在持久性中更改与连接相关的信息.xml)。

现在,这是一个特定于PostgreSQL的问题还是什么?


答案 1

不幸的是,PostgreSQL JDBC驱动程序选择了一种表示非JDBC标准类型代码的方式。他们只是简单地将它们全部映射到Types.OTHER。长话短说,您需要启用一个特殊的休眠类型映射来处理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 注册为默认的 Hibernate 类型映射,用于公开为 java.util.UUID 的所有属性。这在文档 @ http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch06.html#types-registry


答案 2

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

}

只需将此类添加到持久性配置中,并使用 对 UUID 字段进行批注即可。@Column(columnDefinition="uuid")