How does the JPA @SequenceGenerator annotation work

前端 未结 5 1209
轮回少年
轮回少年 2020-11-27 03:43

I am learning JPA and have confusion in the @SequenceGenerator annotation.

To my understanding, it automatically assigns a value to the numeric identity

5条回答
  •  一个人的身影
    2020-11-27 04:38

    Since these questions are very common when using JPA ad Hibernate, this answer is base don this article I wrote on my blog.

    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 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 tABELE 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.IDENTITYstrategy 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:

    • hi/lo
    • pooled or pooled-lo

    These optimizers are meat to reduce the number of database sequence calls, so they multiply the number of identifier values that ca 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, as explained in this article.

    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)
    

    Check out this article for more details.

提交回复
热议问题