有没有办法将 Postgres 的 UUID 生成与 Hibernate 的 IDENTITY ID 生成策略一起使用?

Posted

技术标签:

【中文标题】有没有办法将 Postgres 的 UUID 生成与 Hibernate 的 IDENTITY ID 生成策略一起使用?【英文标题】:Is there a way to use Postgres' UUID generation with Hibernate's IDENTITY ID generation strategy? 【发布时间】:2017-04-12 14:19:37 【问题描述】:

我正在使用 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 的生成策略。有没有办法让它工作?

【问题讨论】:

有理由只使用数据库 UUID 吗? 便携性。有些记录不是通过 Hibernate 创建的。 【参考方案1】:

你可以使用策略:AUTO

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

这里是a working example

【讨论】:

使用GenerationType.AUTO不会让数据库生成uuid,uuid是jvm生成的【参考方案2】:

解决此问题的一种方法是创建一个实现ResultSetIdentifierConsumer 的自定义用户类型。例如,创建一个名为 PostgresIdUUIDType 的类,该类扩展 PostgresUUIDType 并另外实现接口 ParameterizedType 用于配置:

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import java.util.TimeZone;
import java.util.UUID;

import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.id.ResultSetIdentifierConsumer;
import org.hibernate.type.PostgresUUIDType;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.usertype.ParameterizedType;

public class PostgresIdUUIDType
    extends PostgresUUIDType
    implements ResultSetIdentifierConsumer, ParameterizedType 

  private String idColumnName = "id";

  @Override
  public String getName() 
    return "pg-id-uuid";
  

  @Override
  public void setParameterValues(Properties params) 
    idColumnName = params.getProperty("column");
  

  @Override
  public UUID consumeIdentifier(ResultSet resultSet) throws IdentifierGenerationException 
    try 
      return nullSafeGet(resultSet, idColumnName, wrapperOptions());
     catch (SQLException e) 
      throw new IdentifierGenerationException("Error converting type", e);
    
  

  private WrapperOptions wrapperOptions() 
    return new WrapperOptions() 
      @Override
      public boolean useStreamForLobBinding() 
        return false;
      

      @Override
      public LobCreator getLobCreator() 
        return null;
      

      @Override
      public SqlTypeDescriptor remapSqlTypeDescriptor(final SqlTypeDescriptor sqlTypeDescriptor) 
        return PostgresUUIDSqlTypeDescriptor.INSTANCE;
      

      @Override
      public TimeZone getJdbcTimeZone() 
        return TimeZone.getDefault();
      
    ;
  

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

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.TypeDefs;

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

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type="pg-id-uuid", parameters = @Parameter(name = "column", value = "id_column_name"))
    private UUID id;

    ...


@Parameter 列可以指定要使用的不同数据库列,而不是默认提供的id 列。类似于@Column(name = "tag_id") 的工作原理。

【讨论】:

【参考方案3】:

应为@GeneratedValue 使用GenerationType.AUTOGenerationType(默认为AUTO)策略

(可选)持久性提供者必须使用的主键生成策略来生成带注释的实体主键。

GenerationType strategy() default AUTO;

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

GL

Source

【讨论】:

这个答案与@Maksim Kostromin 的答案有何不同?其次,问题是关于 Java,而不是 Kotlin。 您需要图纸吗? AUTO是默认的,列名是uuid而不是id,最好有注解匹配db。问题是JVM,而不是语言。你不了解 Kotlin 并不意味着它不会为其余部分增加价值,你可以使用转换器。

以上是关于有没有办法将 Postgres 的 UUID 生成与 Hibernate 的 IDENTITY ID 生成策略一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

是否有与实现无关的方式让 SQL DB 提供 UUID?

如何在 SQLAlchemy 中使用 UUID?

如何将 Django 的身份验证用户模型配置为具有 UUID(Postgres DB)

尝试将行插入表因为带有sequelize.js的UUID外键时出错

有啥方法可以从字符串生成相同的 UUID

SQL 中有没有办法将目录中包含的所有 .csv 导入我的 postgres 表? (窗口操作系统)