You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate 6.0及以上版本如何委托PostgreSQL生成UUID?

Hibernate 6.x 中委托PostgreSQL生成UUID的推荐实现方式

背景

我通过Liquibase变更集定义了如下数据表,明确指定由PostgreSQL负责UUID的生成:

<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
 
    <changeSet author="..." id="uuid-ossp-extension">
        <sql>CREATE EXTENSION IF NOT EXISTS "uuid-ossp"</sql>
    </changeSet>
 
    <changeSet author="example" id="widgets-table">
        <createTable tableName="widgets">
            <column name="widget_id" type="uuid" defaultValueComputed="uuid_generate_v1mc()">
                <constraints nullable="false" primaryKey="true" primaryKeyName="widget_pk"/>
            </column>
            <column name="name" type="varchar(10)">
                <constraints nullable="false"/>
            </column>
        </createTable>
    </changeSet>
 
</databaseChangeLog>

使用Spring JdbcTemplate时,可通过如下方式实现保存数据并返回生成的UUID:

@Repository
@RequiredArgsConstructor
public class WidgetRepository {

    public static final String INSERT_QUERY = "INSERT INTO widgets(name) VALUES (:name)";


    private final NamedParameterJdbcTemplate template;

    public UUID saveAndReturn(Widget widget) {
        var params = new MapSqlParameterSource(Map.of("name", widget.getName()));
        var generatedKeyHolder = new GeneratedKeyHolder();
        var generateKeyColumns = new String[]{"widget_id"};
        template.update(INSERT_QUERY, params, generatedKeyHolder, generateKeyColumns);
        return generatedKeyHolder.getKeyAs(UUID.class);
    }

    ...

}

Hibernate 6.0及以上版本提供了新的UuidGenerator注解,可简化由Hibernate自行生成UUID的逻辑:

@Entity
@Table(name = "widgets")
public class Widget {
 
    @Id
    @UuidGenerator(style = TIME)
    @Column(name = "widget_id")
    private UUID id;
 
    @Column
    private String name;

    ...
}

但该UuidGenerator机制不支持委托PostgreSQL生成UUID,此前相关方案依赖的UUIDGenerationStrategy接口现已废弃,请问Hibernate 6.0及以上版本中的推荐实现方式是什么?


解决方案

在Hibernate 6.x中,要实现委托PostgreSQL数据库生成UUID,推荐以下两种方式:

方式一:使用@GeneratedValue配合GenerationType.IDENTITY

由于数据表已通过defaultValueComputed指定PostgreSQL自动生成UUID(uuid_generate_v1mc()),只需在实体类ID字段配置@GeneratedValue(strategy = GenerationType.IDENTITY),让Hibernate识别这是数据库生成的主键:

@Entity
@Table(name = "widgets")
public class Widget {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "widget_id", columnDefinition = "uuid")
    private UUID id;
 
    @Column(name = "name", length = 10, nullable = false)
    private String name;

    // 构造器、getter/setter等
}

这种方式下,Hibernate插入数据时会忽略ID字段的赋值,由数据库通过默认值生成UUID,插入后自动将生成的ID值返回给实体对象,是最简洁的方案。

方式二:自定义标识符生成器(适配灵活场景)

如果需要更精细的控制(比如切换不同UUID生成函数),可实现Hibernate 6.x的IdentifierGenerator接口自定义生成器:

  1. 自定义生成器类:
public class PostgreSqlUuidGenerator implements IdentifierGenerator {

    @Override
    public Object generate(SharedSessionContractImplementor session, Object entity) throws HibernateException {
        // 调用PostgreSQL指定的UUID生成函数
        return session.createNativeQuery("SELECT uuid_generate_v1mc()", UUID.class)
                .uniqueResult();
    }
}
  1. 在实体类中指定使用该生成器:
@Entity
@Table(name = "widgets")
public class Widget {
 
    @Id
    @GeneratedValue(generator = "postgresql-uuid")
    @GenericGenerator(name = "postgresql-uuid", type = PostgreSqlUuidGenerator.class)
    @Column(name = "widget_id", columnDefinition = "uuid")
    private UUID id;
 
    @Column(name = "name", length = 10, nullable = false)
    private String name;

    // 构造器、getter/setter等
}

这种方式可自定义生成逻辑,比如替换为uuid_generate_v4()函数,适合需要动态调整生成策略的场景。


注意事项:

  • 确保PostgreSQL已安装uuid-ossp扩展(你的Liquibase变更集已处理此步骤)
  • 使用GenerationType.IDENTITY时,Hibernate会自动适配PostgreSQL主键生成逻辑,无需额外配置
  • 自定义生成器时,需保证生成函数与数据库默认值逻辑一致,避免主键冲突

内容的提问来源于stack exchange,提问作者toolkit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 12:50:39