- Overview
- Auto Incremented Primary Key
- Vendor Specific Flyway Migrations
- UUID Primary Key
- UUID RFC 4122 Primary Key
- Natural Primary Key
- Composite Primary Key
- Embedded Composite Primary key
We use annotation for specify the primary key with Hibernate:
@Id
@GeneratedValue(strategy = Generation.AUTO)
There are different primary keys can be used:
- Numeric Primary Keys
GenerationType.AUTO
: let Hibernate pick - best practice is to specifyGenerationType.SEQUENCE
: use database sequence (this is NOT a feature of MySQL)GenerationType.IDENTITY
: use auto-incremented database columnsGenerationType.TABLE
: use database table to simulate sequence
- UUID Primary Keys
- Common to use as primary key, it can help index performance.
- The drawback is the UUID primary keys use more disk space.
- Hibernate implements a custom generator by default, but it can be configured to generate a IETF RFC 4122 compliant UUID.
- Natural Primary Keys
- A unique value with business meaning outside of the database.
- A UPC or ISBN could be considered a natural key, since both are expected to be unique.
- It's common in old legacy databases, but it's NOT considered the best practice.
- Composite Primary Keys
- Two values with business meaning combined to make a unique value
- It's common in old legacy databases, but it's NOT considered the best practice.
- Small Table: favor Numeric Primary Keys (
Integer
orLong
) for few million rows. - Large Table: favor UUID if disk space allows for 10's of millions or billions rows.
- Generally avoid using Natural Primary Keys or Composite Primary Keys.
First, use @GeneratedValue(strategy = GenerationType.IDENTITY)
annotation to class:
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
Then add V4__autoincrement_pk.sql
for Flyway migrations:
alter table book change id id BIGINT auto_increment;
alter table author change id id BIGINT auto_increment;
In the previous seciton, the V4__autoincrement_pk.sql
works fine for MySQL, but it doesn't work with H2 Database. To solve this problem, we're going to setup for the vendor-specific migrations:
- Edit
application.properties
and addspring.flyway.locations
.spring.flyway.locations=classpath:db/migration/common,classpath:db/migration/{vendor}
- Create directories for different database.
./src/main/resources/db/migration/common
./src/main/resources/db/migration/h2
- Add
V4.1__h2_auto.sql
for H2 database:drop table if exists book; drop table if exists author; create table book ( id IDENTITY not null, isbn varchar(255), publisher varchar(255), title varchar(255), author_id BIGINT, primary key (id) ); create table author ( id IDENTITY not null, first_name varchar(255), last_name varchar(255), primary key (id) );
@Entity
public class AuthorUuid {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Type(type = "org.hibernate.type.UUIDCharType")
@Column(length = 36, columnDefinition = "varchar(36)", updatable = false, nullable = false)
private UUID id;
...
}
@Entity
public class BookUuid {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(columnDefinition = "BINARY(16)", updatable = false, nullable = false)
private UUID id;
...
}
To deal with the Hibernate and H2 Database UUID validation error, we should use
"VARBINARY(16)"
instead of"BINARY(16)"
.
@Entity
public class BookNatural {
@Id
private String title;
private String isbn;
private String publisher;
...
}
@Entity
@IdClass(NameId.class)
public class AuthorComposite {
@Id
private String firstName;
@Id
private String lastName;
private String country;
...
}
@Entity
@Table(name = "author_composite")
public class AuthorEmbedded {
@EmbeddedId
private NameId nameId;
private String country;
...
}