32

我正在尝试在 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。

我已经或多或少地看到了许多关于相同问题的问题,但它们都很老,似乎没有一个直接的答案。

我想以一种标准的方式来实现这一点,而不是诉诸丑陋的黑客。但是,如果这只能通过(丑陋的)黑客来实现,那么这就是我要做的。但是,我不想将 UUID 作为 varchar 存储在数据库中,因为这不利于性能。另外,如果可能的话,我不想在我的代码中引入 Hibernate 依赖项。

任何帮助将不胜感激。

更新 1 (2012-07-03 12:15 pm)

嗯,嗯,嗯......这有点有趣,我使用 JTDS 驱动程序(v1.2.5)和 SQL Server 2008 R2 测试了完全相同的代码(纯 UUID,没有转换——上面发布的代码的第一个版本)和,你猜怎么着,它就像一个魅力(当然我必须在persistence.xml 中更改与连接相关的信息)。

现在,它是特定于 PostgreSQL 的问题还是什么?

4

6 回答 6

40

不幸的是,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

于 2012-10-10T17:16:40.003 回答
18

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").

于 2013-06-26T15:12:55.300 回答
15

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

@Id
@GeneratedValue
@Column( columnDefinition = "uuid", updatable = false )
public UUID getId() {
    return id;
}
于 2016-12-20T04:38:17.217 回答
3

较新版本>= 8.4-701的 Postgresql JDBC 驱动程序正确处理java.util.UUID映射。休眠也是如此>= 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.
于 2014-09-09T09:28:35.507 回答
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;
    }
}
于 2014-07-30T08:27:39.407 回答
0

在 postgresql url 连接上添加这个标志:?stringtype=unspecified

像那样

jdbc:postgresql://localhost:5432/yourdatabase?stringtype=unspecified

于 2017-12-07T11:17:13.053 回答