有没有办法将 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.AUTO
或GenerationType
(默认为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 生成策略一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Django 的身份验证用户模型配置为具有 UUID(Postgres DB)