Hibernate 6 upgrades changes primary key composition in Envers audit table

Hello friends,

Im working through an upgrade from Hibernate 5.5 + Spring Boot 2.7 to Hibernate 6.4 and Spring Boot 3.2. I use the Hibernate SchemaExport tool to generate my database schema, and its been very helpful when dealing with all the needed migrations between 5.5 and 6.4. I also use Hibernate Envers to create an unique audit table for each audited entity. I’ve been using this pattern across multiple services successfully for years. However I’ve run into a bit of a roadbump with the migration. For some reason, the schema that the SchemaExport tool generates for Hibernate 6 changes the primary key composition of the audit tables.

I’ve carefully read through all the relevant Hibernate migration guides but can’t find anything that explains one odd behavior I’m seeing. I can’t pinpoint if its a problem with Hibernate Envers, Hibernate SchemaExport, or some combination of the two. I’d really, really rather not do a primary key migration on every single audit table in every single database I own, so I would really appreciate some guidance here.

Consider a fairly simple Entity class named TagEntity.java

@Entity
@Table(name = "tag", uniqueConstraints = {
        @UniqueConstraint(name = "UK_tag_name", columnNames = {"name"})
})
@Audited
@Getter
@Setter
@ToString
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = true)
public class TagEntity {
    @Id
    @GeneratedValue
    @UuidGenerator
    private UUID id;

    @Basic
    @Column(name = "name", length = 132, nullable = false)
    @NotBlank(message = "{tag.name.required}")
    @EqualsAndHashCode.Include
    private String name;

    @Basic
    @Column(name = "description")
    private String description;
}

In Hibernate 5 and 6, the SchemaExport tool generates the same schema for the tag table

Note: While I’m trying to upgrade from 5.5 to 6.4.4.Final, in order to narrow down any possible causes I generated all below schemas using these specific versions:

Hibernate 5.6.15.Final (same behavior as 5.5) & Hibernate 6.0.2.Final (same behavior as 6.4.4.Final)

create table tag (
         id CHAR(36) not null,
         date_created datetime not null default CURRENT_TIMESTAMP,
         last_updated datetime not null default CURRENT_TIMESTAMP,
         version bigint not null,
         description varchar(255),
         name varchar(132) not null,
         primary key (id)
     ) engine=InnoDB;

However, Hibernate 5 and 6 differ in how the SchemaExport tool generates the tag audit table, with the one change being the primary key

Hibernate 5

create table tag_aud (
        id CHAR(36) not null,
        REV bigint not null,
        REVTYPE tinyint,
        REVEND bigint,
        REVEND_TSTMP datetime(6),
        description varchar(255),
        description_MOD bit,
        name varchar(132),
        name_MOD bit,
        primary key (id, REV)
    ) engine=InnoDB;

Hibernate 6

     create table tag_aud (
         id CHAR(36) not null,
         REV bigint not null,
         REVTYPE tinyint,
         REVEND bigint,
         REVEND_TSTMP datetime(6),
         description varchar(255),
         description_MOD bit,
         name varchar(132),
         name_MOD bit,
         primary key (REV, id)
     ) engine=InnoDB; 

And its not just the tag table, this is happening with every audit table in our database.

Another example, with a more complex key

Hibernate 5

create table available_part_component_aud (
    REV bigint not null,
    available_part_id CHAR(36) not null,
    component_id CHAR(36) not null,
    REVTYPE tinyint,
    REVEND bigint,
    REVEND_TSTMP datetime(6),
    primary key (REV, available_part_id, component_id)
) engine=InnoDB;

Hibernate 6

create table available_part_component_aud (
    REV bigint not null,
    available_part_id CHAR(36) not null,
    component_id CHAR(36) not null,
    REVTYPE tinyint,
    REVEND bigint,
    REVEND_TSTMP datetime(6),
    primary key (available_part_id, REV, component_id)
) engine=InnoDB;

Of course theres a bit more code behind the scenes than what is presented here (for example setting UUID type to CHAR in Hibernate 6 config), I’ve tried to distill down the fundamentals for appropriate presentation on a public forum. When encountering this behavior, nothing about the codebase has changed besides upgrading our dependencies to SB3 + Hibernate 6. If anyone can recommend a way to return to the previous key generation behavior, that would be great. Thanks for reading!

I understand that it might be desirable to keep the same column order for unique constraints like Hibernate ORM 5 did, but I have no clue what might be responsible for that reordering.
I would recommend you to create a reproducer with our test case template and if you are able to reproduce the issue, create a bug ticket in our issue tracker and attach that reproducer.