How to use a JVM or database auto-generated UUID identifier with JPA and Hibernate
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.
So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!
Introduction
In this article, we are going to see how to use a UUID entity identifier that is auto-generated by Hibernate either in the JVM or using database-specific UUID functions.
Our Post
entity looks as follows:
The Post
entity has a UUID identifier and a title. Now, let’s see how we can map the Post
entity so that the UUID identifier be auto-generated for us.
GenerationType.AUTO
When using JPA, we can use the GenerationType.AUTO
strategy of the @GeneratedValue
annotation to assign numerical identifier automatically, based on an IDENTITY column, a SEQUENCE or the infamous TABLE generator.
However, few might know that GenerationType.AUTO
can be used for UUID identifiers as well:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue(strategy = GenerationType.AUTO) private UUID id; private String title; //Getters and setters omitted for brevity }
Now, when persisting a Post
entity:
Post post = new Post(); post.setTitle("High-Performance Java Persistence"); entityManager.persist(post);
Hibernate generates the following SQL INSERT statement:
INSERT INTO post ( title, id ) VALUES ( 'High-Performance Java Persistence', 'b5607d38-8fc1-43ef-b44e-34967083c80a' )
Even batching works as expected:
for (int i = 0; i < 3; i++) { Post post = new Post(); post.setTitle( String.format( "High-Performance Java Persistence, Part %d", i + 1 ) ); entityManager.persist(post); }
Hibernate generating a single SQL INSERT statement with 3 bind parameter value sets:
Query:[ "insert into post (title, id) values (?, ?)" ], Params:[ (High-Performance Java Persistence, Part 1, 7176589b-a3ca-472f-bf00-c253c351ddcc), (High-Performance Java Persistence, Part 2, a4269fb4-07c9-447a-9d65-f443c074de20), (High-Performance Java Persistence, Part 3, e33962a0-d841-48b1-8f43-caf98116f3ee) ]
Database-generated UUID
Now, if we don’t want the UUID to be generated by the JVM, and want to use database-specific functions, we need to provide an implementation of the org.hibernate.id.UUIDGenerationStrategy
interface:
public class PostgreSQLUUIDGenerationStrategy implements UUIDGenerationStrategy { @Override public int getGeneratedVersion() { return 4; } @Override public UUID generateUUID( SharedSessionContractImplementor session) { return ((Session) session).doReturningWork(connection -> { try( Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery( "select uuid_generate_v4()" ) ) { while (resultSet.next()) { return (UUID) resultSet.getObject(1); } } throw new IllegalArgumentException("Can't fetch a new UUID"); }); } }
The getGeneratedVersion
method defines what type of UUID we are generating, according to the IETF RFC 4122 standard. In our case, 4
stands for variant 4 (random) generator strategy.
Because we are using PostgreSQL, we also need to create the uuid-ossp
extension before using the UUID-specific functions:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
Now, we can call the uuid_generate_v4
function to get a variant 4 UUID based on IETF RFC 4122 specification.
To provide the PostgreSQLUUIDGenerationStrategy
to our Post
entity, we have to use the Hibernate-specific @GenericGenerator
:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue( strategy = GenerationType.AUTO, generator = "pg-uuid" ) @GenericGenerator( name = "pg-uuid", strategy = "uuid2", parameters = @Parameter( name = "uuid_gen_strategy_class", value = "com.vladmihalcea.book.hpjp.hibernate.identifier.uuid.PostgreSQLUUIDGenerationStrategy" ) ) private UUID id; private String title; //Getters and setters omitted for brevity }
The uuid2
strategy stands for org.hibernate.id.UUIDGenerator
which we want to use instead of the legacy org.hibernate.id.UUIDHexGenerator
that’s registered under the uuid
name in Hibernate.
The @Parameter
attribute is used to customize the UUID generation strategy via the uuid_gen_strategy_class
parameter value which takes the fully-qualified class name of the org.hibernate.id.UUIDGenerationStrategy
interface implementation.
And, that’s it!
Now, when persisting 3 Post
entities, Hibernate generates the following SQL statements:
select uuid_generate_v4() select uuid_generate_v4() select uuid_generate_v4() Query:[ "insert into post (title, id) values (?, ?)" ], Params:[ (High-Performance Java Persistence, Part 1, 9eb52a9b-fb81-4930-b0cd-079a447ed2ba), (High-Performance Java Persistence, Part 2, 2a69ec7d-a147-4c71-8a20-9ba760de0149), (High-Performance Java Persistence, Part 3, e7616832-bb4e-470a-8df4-0534ab56d960) ]
Notice the calls to the uuid_generate_v4
PostgreSQL function which is used to assign the UUID identifier values.
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
You can either allow Hibernate to use the Java-based UUID generation strategy, or you can delegate this task to the database. The latter option requires providing an implementation of the org.hibernate.id.UUIDGenerationStrategy
which is rather straightforward.
However, while auto-generating a UUID identifier when using Hibernate is fairly easy, the standard UUIDs are not a good fit for Primary Keys, as you are better off using a time-sorted TSID instead. For more details about this topic, check out this article.

Hi Vlad.. thank you so much for your interesting topics and clear posts.
I just would like to bring to your attention the new built-in function “gen_random_uuid ()” to generate random UUIDs in PostgreSQL 14:
https://www.postgresql.org/docs/14/functions-uuid.html
I haven’t used it personally (yet), but it’s a built-in function that doesn’t require the “uuid-ossp” library.
Thanks for pointing that out.
However, I use the
Tsid
, as it’s much better than UUID.