使用JPA在PostgreSQL中保留UUID

时间:2012-07-01 17:54:35

标签: java hibernate postgresql jpa uuid

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

7 个答案:

答案 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();
}

还有一些事情需要考虑:

  1. 是否使用ID,UUID或两者。有quick discussion over this
  2. 将'uuid'用于名称而不是'id',这会产生误导。
  3. 从UUID中删除' - '符号,保存4个字节。
  4. 如果使用Spring,则在@PrePersist部分生成UUID。