Now, back to your questions:
Q1. Does this sequence generator make use of the database's increasing
numeric value generating capability or generates the number on its
own?
By using the GenerationType.SEQUENCE
strategy on the @GeneratedValue
annotation, the JPA provider will try to use a database sequence object of the underlying database that supports this feature (e.g., Oracle, SQL Server, PostgreSQL, MariaDB).
If you are using MySQL, which doesn't support database sequence objects, then Hibernate is going to fall back to using the GenerationType.TABLE
instead, which is undesirable since the TABLE generation performs badly.
So, don't use the GenerationType.SEQUENCE
strategy with MySQL.
Q2. If JPA uses a database auto-increment feature, then will it work
with datastores that don't have auto-increment feature?
I assume you are talking about the GenerationType.IDENTITY
when you say database auto-increment feature
.
To use an AUTO_INCREMENT
or IDENTITY
column, you need to use the GenerationType.IDENTITY
strategy on the @GeneratedValue
annotation.
Q3. If JPA generates numeric value on its own, then how does the JPA
implementation know which value to generate next? Does it consult with
the database first to see what value was stored last in order to
generate the value (last + 1)?
The only time when the JPA provider generates values on its own is when you are using the sequence-based optimizers, like:
These optimizers are meat to reduce the number of database sequence calls, so they multiply the number of identifier values that can be generated using a single database sequence call.
To avoid conflicts between Hibernate identifier optimizers and other 3rd-party clients, you should use pooled
or pooled-lo
instead of hi/lo
. Even if you are using a legacy application that was designed to use hi/lo, you can migrate to the pooled
or pooled-lo
optimizers.
Q4. Please also shed some light on sequenceName
and allocationSize
properties of @SequenceGenerator
annotation.
The sequenceName
attribute defines the database sequence object to be used to generate the identifier values. IT's the object you created using the CREATE SEQUENCE
DDL statement.
So, if you provide this mapping:
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "seq_post"
)
@SequenceGenerator(
name = "seq_post"
)
private Long id;
Hibernate is going to use the seq_post
database object to generate the identifier values:
SELECT nextval('hibernate_sequence')
The allocationSize
defines the identifier value multiplier, and if you provide a value that's greater than 1, then Hibernate is going to use the pooled
optimizer, to reduce the number of database sequence calls.
So, if you provide this mapping:
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "seq_post"
)
@SequenceGenerator(
name = "seq_post",
allocationSize = 5
)
private Long id;
Then, when you persist 5 entities:
for (int i = 1; i <= 5; i++) {
entityManager.persist(
new Post().setTitle(
String.format(
"High-Performance Java Persistence, Part %d",
i
)
)
);
}
Only 2 database sequence calls will be executed, instead of 5:
SELECT nextval('hibernate_sequence')
SELECT nextval('hibernate_sequence')
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 1', 1)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 2', 2)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 3', 3)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 4', 4)
INSERT INTO post (title, id)
VALUES ('High-Performance Java Persistence, Part 5', 5)