Hibernate Tip: How does Hibernate’s native ID generator work
Take your skills to the next level!
The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.
Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question for a future Hibernate Tip, please post a comment below.
Question:
One of the readers of my article about using Hibernate with a MySQL database asked the following question:
What is the difference between the following two recommended approaches concerning the primary keys?
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(generator = "native") @GenericGenerator(name = "native", strategy = "native")
Solution:
As so often in software development, the answer to that question is: “It depends …”. In this case, it depends on the Dialect that you configured in your persistence.xml.
The native strategy
When you use a @GenericGenerator that references the native strategy, Hibernate uses the strategy natively supported by the configured Dialect. You can find the corresponding code in the of the Dialect class. Here’s is the code that’s used in Hibernate 5.4.
public String getNativeIdentifierGeneratorStrategy() { if ( getIdentityColumnSupport().supportsIdentityColumns() ) { return "identity"; } else { return "sequence"; } }
For all commonly used databases, except MySQL, this method returns the String “sequence”. If you’re using a MySQL dialect, it returns “identity”.
Using the native strategy with different dialects
Let’s use the following, simple entity with a MySQL and a PostgreSQL database.
@Entity public class Author { @Id @GeneratedValue(generator = "native") @GenericGenerator(name = "native", strategy = "native") private Long id; @Version private int version; private String firstName; private String lastName; ... }
When you persist a new Author entity using the PostgreSQL dialect, you can see that Hibernate uses the sequence native to generate the primary key value. And in the next step, it inserts the new record.
14:03:27,709 DEBUG [org.hibernate.SQL] - select nextval ('native') 14:03:27,742 INFO [org.thoughts.on.java.model.TestIdentityStrategy] - After persist 14:03:27,758 DEBUG [org.hibernate.SQL] - insert into Author (firstName, lastName, version, id) values (?, ?, ?, ?)
If you use a MySQL database instead, you can see that Hibernate utilizes an auto-incremented column instead.
14:05:15,739 DEBUG [org.hibernate.SQL] - insert into Author (firstName, lastName, version) values (?, ?, ?) 14:05:15,760 DEBUG [org.hibernate.id.IdentifierGeneratorHelper] - Natively generated identity: 1
The differences between native and identity strategy
So, as long as you use both mappings with a MySQL database, the result will be the same. But there are still a few differences:
- The behavior of the native strategy changes if your database dialect returns a different strategy as the natively supported one. That could happen because you now use a different database dialect or the internal implementation of the dialect changed.
- The @GenericGenerator mapping is much harder to read because it depends on the implementation of your database dialect.
- The @GenericGenerator annotation is Hibernate-specific. So, you can’t use this mapping with any other JPA implementation.
Mapping Recommendations
If you’ve read some of my other tutorials, you can probably guess my preferred mapping. I strongly recommend using the IDENTITY mapping instead of the native one. There are multiple reasons for that. The most obvious ones are the better readability and better portability to other JPA implementations.
But you also need to keep in mind that the generation of primary keys can have a significant impact on the performance of your application. I, therefore, want to define the strategy explicitly and don’t rely on any internal implementations.
I don’t see the adaptability of the native strategy to different database dialects as a huge advantage. For almost all dialects, Hibernate uses the SEQUENCE strategy anyways. And if you need to support MySQL databases, you can easily override the primary key strategy in your mapping file.
Learn more:
If you are interested in primary key mappings, you should also read the following articles:
- 5 Primary Key Mappings for JPA and Hibernate Every Developer Should Know
- How to generate primary keys with JPA and Hibernate
- How to generate UUIDs as primary keys with Hibernate
Hibernate Tips Book
Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.
It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.
thanks for the information