有没有办法使用Postgres'使用Hibernate的IDENTITY ID生成策略生成UUID?

时间:2016-11-28 18:54:00

标签: java postgresql hibernate jpa spring-boot

我使用Spring Boot 1.4.1(包括Hibernate 5)和Postgres 9.6,我试图创建一个具有UUID ID的实体但是使用Postgres' UUID代而不是Hibernate代。许多类似的问题都说将列类型设置为pg-uuid。这似乎适用于非数据库生成的ID列,但当我尝试将其用于ID列时,我得到了

org.hibernate.id.IdentifierGenerationException: unrecognized id type : pg-uuid -> java.util.UUID

所以看起来Hibernate正确地应用了类型,但没有转换它。

以下是我的实体的ID列的设置方式:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@org.hibernate.annotations.Type(type="pg-uuid")
private UUID id;

该表的设置类似于以下内容(已安装uuid-ossp

create table example (
    id UUID NOT NULL DEFAULT uuid_generate_v1mc(),
    ...
);

我希望让数据库生成UUID并且不想使用Hibernate的生成策略。有没有办法让这个工作?

3 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是创建实现ResultSetIdentifierConsumer的自定义UserType。对于一个快速而肮脏的示例,创建一个名为PostgresIdUUIDType的类,在实现接口时扩展PostgresUUIDType

public class PostgresIdUUIDType extends PostgresUUIDType implements ResultSetIdentifierConsumer {

    // Naively look for a name that contains "id" in it, case insensitive
    private static final Pattern idPattern = Pattern.compile("id", Pattern.CASE_INSENSITIVE);

    public String getName() {
        return "pg-id-uuid";
    }

    @Override
    public UUID consumeIdentifier(final ResultSet resultSet) throws IdentifierGenerationException {
        try {
            final int columnCount = resultSet.getMetaData().getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                int columnType = resultSet.getMetaData().getColumnType(i);
                // Postgres driver maps UUID to OTHER
                if (Types.OTHER == columnType) {
                    final String name = resultSet.getMetaData().getColumnName(i);
                    if (idPattern.matcher(name).matches()) {
                        return nullSafeGet(resultSet, name, new WrapperOptions() {
                            @Override
                            public boolean useStreamForLobBinding() {
                                return false;
                            }
                            @Override
                            public LobCreator getLobCreator() {
                                return null;
                            }
                            @Override
                            public SqlTypeDescriptor remapSqlTypeDescriptor(final SqlTypeDescriptor sqlTypeDescriptor) {
                                return PostgresUUIDSqlTypeDescriptor.INSTANCE;
                            }
                        });
                    }
                }
            }
            throw new IdentifierGenerationException("Could not find id column");
        } catch (SQLException e) {
            throw new IdentifierGenerationException("Error converting type", e);
        }
    }
}

然后在您的实体中,定义自定义类型并将其用于您的ID列,如下所示:

@TypeDefs({@TypeDef(name = "pg-id-uuid", typeClass = PostgresIdUUIDType.class) })
@Entity
public class Example {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @org.hibernate.annotations.Type(type="pg-id-uuid")
    private UUID id;

    ...

}

到目前为止,这似乎适用于我的有限测试。最大的问题是PostgresIdUUIDType天真地假设UUID ID列是名称中第一个带'id'的列,不区分大小写。如果有人想知道如何更好地确定哪一列实际上是ID列,我会很感激调整。

答案 1 :(得分:1)

只需使用策略:自动

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;

这里是worked example

答案 2 :(得分:-1)

将策略GenerationType.AUTO(默认)用于@GeneratedValue

@Entity
@Table("custom")
data class Custom(
        @Id @GeneratedValue @Column(name = "column_uuid") val columnUUID: UUID
)

GL

Source