使用 JPA 在 PostgreSQL 中保留 UUID

问题描述 投票:0回答:6

我正在尝试在 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 特定的问题还是什么?

java hibernate postgresql jpa uuid
6个回答
43
投票

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


19
投票

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 字段即可。


18
投票

要使其与 Hibernate 5.1.x 一起使用,您可以关注 Steve Ebersole 在此处评论

@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

查看详细信息https://stackoverflow.com/a/780922/173149:

将数据库uuid类型映射到java.util.UUID。这仅适用于 相对较新的服务器 (8.3) 和 JDK (1.5) 版本。


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

0
投票

在 postgresql url 连接上添加此标志:

?stringtype=unspecified

这样

jdbc:postgresql://localhost:5432/yourdatabase?stringtype=unspecified
© www.soinside.com 2019 - 2024. All rights reserved.