Hibernate @TableGenerator
for
Primary Key Generation in distributed systems
In the world of Java and Hibernate, managing unique identifiers for entities is a critical task, especially in distributed systems. Hibernate offers a powerful tool for this — @TableGenerator
. This article will guide you step by step through setting up and using @TableGenerator
, as well as explain how to create the necessary SQL queries to support this method of identifier generation.
Hi, this is Paul, and welcome to the Hibernate guide. Today we will discuss how to use @TableGenerator
for organizing primary key generation in distributed systems.
What is @TableGenerator
?
@TableGenerator
is an annotation in Hibernate that allows customizing the generation of primary keys using a special table to store the next identifier value? This method provides flexibility and control over the identifier generation process, which is particularly useful in distributed systems.
Example
DB schema:
CREATE TABLE employee (
id BIGINT NOT NULL,
name VARCHAR(255),
PRIMARY KEY (id)
);
To start, let’s consider an example of an Employee
entity that uses @TableGenerator
to generate unique identifiers:
import jakarta.persistence.*;
import lombok.*;
@Entity
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "employee_gen")
@TableGenerator(
name = "employee_gen",
table = "id_gen",
pkColumnName = "gen_key",
valueColumnName = "gen_value",
pkColumnValue = "employee_id",
allocationSize = 1
)
private Long id;
@Column(name = "name")
private String name;
// equals and hashCode
}
name
: Generator name used in annotation@GeneratedValue
.table
: Table name used for storing identifier values.pkColumnName
: Column name in the table containing the key name.valueColumnName
: Column name containing the following key value.pkColumnValue
: The value inpkColumnName
, which identifies the row containing the next identifier value for the given entity.allocationSize
: The number of values allocated at once and stored in memory. It allows reducing the number of database queries for new values.
To implement the mechanism described by @TableGenerator
in Hibernate, it will be necessary to create a special table for storing the current identifier values. Here’s what the SQL for creating such a table might look like, based on the previous Employee entity example:
CREATE TABLE id_gen (
gen_key VARCHAR(255) NOT NULL,
gen_value BIGINT NOT NULL,
PRIMARY KEY (gen_key)
);
In this table, gen_key
will store a unique name (or key) for each entity or group of entities for which unique identifiers need to be generated. gen_value
will store the next identifier value that will be allocated.
For example, for the Employee entity we discussed, a row in this table might look like this:
INSERT INTO id_gen (gen_key, gen_value) VALUES ('employee_id', 1);
Here, employee_id
is the value specified in the pkColumnValue
of the @TableGenerator
annotation, and it indicates that the next identifier for the Employee
entity will start from 1. When Hibernate needs a new identifier, it refers to this table, increments the gen_value
by allocationSize
(in our example by 1, since allocationSize=1
) and uses this new value as the identifier for the new entity.
If the application needs to create a new Employee
record, Hibernate will first update the record in the id_gen
table by incrementing gen_value
:
UPDATE id_gen SET gen_value = gen_value + 1 WHERE gen_key = 'employee_id';
Then it uses this new value of gen_value
as the identifier for a new record in the employee
table.
This mechanism allows for avoiding identifier conflicts, especially in distributed systems, and provides more control over the process of generating unique identifiers at the cost of a slight decrease in performance due to the need for additional update and fetch operations from the id_gen
table.
Advantages and disadvantages
Using @TableGenerator
provides significant flexibility in managing entity identifiers, but it’s important to consider the additional database load due to the need to read and update the special identifier table. In some cases, this can lead to reduced performance, especially in situations with high competition for access to this table.
Thank you for reading until the end. Before you go:
- Please consider clapping and following the writer! 👏
- Follow us on Twitter(X), LinkedIn