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

Str*_*ess 7 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;
Run Code Online (Sandbox Code Playgroud)

并且表的设置类似于以下(uuid-ossp已安装)

create table example (
    id UUID NOT NULL DEFAULT uuid_generate_v1mc(),
    ...
);
Run Code Online (Sandbox Code Playgroud)

我宁愿让数据库生成UUID,也不想使用Hibernate的生成策略.有没有办法让这个工作?

Mak*_*min 8

您可以使用策略:AUTO

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
Run Code Online (Sandbox Code Playgroud)

这是一个工作示例

  • 使用 `GenerationType.AUTO` 不会让数据库生成 uuid,uuid 是由 jvm 生成的 (2认同)

Str*_*ess 3

解决此问题的一种方法是创建一个实现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();
      }
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的实体中,定义自定义类型并将其用于 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;

    ...

}
Run Code Online (Sandbox Code Playgroud)

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