Search code examples
springpostgresqlhibernatejpa

Hibernate to delegate UUID generation to postgres


Imagine I have a simple table such as the following, defined using a liquibase changeset

<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>

That is, I want to be explicit about letting postgres compute the UUID.

If I was using Spring JdbcTemplate, I could use something simple like:

@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);
    }

    ...

}

With Hibernate 6.0 onwards, there is a new UuidGenerator annotation, that simplifies Hibernate taking responsibility for generating a UUID:

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

    ...
}

However, this new UUIDGenerator mechanism doesn't seem to support delegating to postgres. https://vladmihalcea.com/uuid-identifier-jpa-hibernate/ suggested an alternative approach, but the UUIDGenerationStrategy it implements is now deprecated.

Does anyone know the preferred mechanism for Hibernate 6.0 onwards?


Solution

  • I tweeted about this here:

    https://twitter.com/1ovthafew/status/1645795161379831811

    The short answer is:

    @Entity
    public class Entity {
        @Generated @Id
        @ColumnDefault("gen_random_uuid()")
        UUID uuid;
    }
    

    Note that Hibernate 6.2 is required.