Search This Blog

Monday 10 June 2013

@GeneratedValue

In our previous posts we saw how the GeneratedValue annotation was used to specify the identifier generator strategy. I decided to look at the various options available in detail
I created a simple class named User with just an identifier column and a name property.
    
    public void setId(Long id) {
        this.id = id;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

    @Column(name = "NAME")
    public String getName() {
        return name;
    }
        //other methods
}
Here the generator type is set to AUTO. This is equivalent to the native generator in Hibernate. I ran the code with ddl creation enabled. The DDL generated is as below:

    create table firstOne.APP_USER (
        id int8 not null,
        NAME varchar(255),
        primary key (id)
    )
    create sequence hibernate_sequence
As seen here, Hibernate created a sequence generator for PostgreSQL. The sequence created by Hibernate however was placed in the default schema and not in the schema declaration provided by me. If I tried to insert a record:
public static void testAUTO() {
    EntityManager entityManager = entityManagerFactory.createEntityManager(); 
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    User user = new User();
    user.setName("Vijay");
    entityManager.persist(user);
    transaction.commit();
}
The logs are as below:
2859 [main] DEBUG org.hibernate.event.def.DefaultPersistEventListener  - saving 
transient instance
2859 [main] DEBUG org.hibernate.SQL  - 
    select
        nextval ('hibernate_sequence')
2875 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener  - generated
 identifier: 1, using strategy: org.hibernate.id.SequenceGenerator
2984 [main] DEBUG org.hibernate.SQL  - 
    insert 
    into
        firstOne.APP_USER
        (NAME, id) 
    values
        (?, ?)
As seen, Hibernate first retrieved the value from the sequence and then executed the insert query.If there are more entities using the AUTO GenerationType, then they will all share the same sequence generator.
I next decided to try IDENTITY GenerationType. This is equivalent to Hibernate's identity strategy. The only change in the code was to the annotation:
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
The DDL generated is:
create table firstOne.APP_USER (
        id  bigserial not null,
        NAME varchar(255),
        primary key (id)
    )
The bigserial is PostgreSQL's way of saying auto-increment. In fact it is not an actual data type. It is actually a convenience way of avoiding manual sequences:
So saying
CREATE TABLE tablename (
colname SERIAL
);
is actually equivalent to :
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer DEFAULT nextval('tablename_colname_seq') NOT NULL);
PostgreSQL manages this internally.
On running the create code again the logs are as below:
3110 [main] DEBUG org.hibernate.event.def.AbstractSaveEventListener  - executing
 identity-insert immediately
3110 [main] DEBUG org.hibernate.persister.entity.AbstractEntityPersister  - Inse
rting entity: com.id.generation.User (native id)
3125 [main] DEBUG org.hibernate.SQL  - 
    insert 
    into
        firstOne.APP_USER
        (NAME) 
    values
        (?)
3172 [main] DEBUG org.hibernate.id.IdentifierGeneratorFactory  - Natively genera
ted identity: 1
The next is the SEQUENCE type. This is equivalent to Hibernate's sequence strategy:
@SequenceGenerator(sequenceName = "APP_USER_ID_SEQ", name = "AppUserIdSequence")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "AppUserIdSequence")
public Long getId() {
This has two annotations.The first is the SequenceGenerator annotation. It provides details of the sequence used. The sequenceName is the name of the sequence in the database. The seconds is the name property. It is like an identifier for this annotation. The same name now appears in the GeneratedValue annotation. It is placed in the generator attribute and ties the two annotations together.
The SequenceGenerator annotation can be placed on the entity class too. The name is what is used to match it to the GeneratedValue and not its position.
The DDL generated for the code is :
create table firstOne.APP_USER (
        id int8 not null,
        NAME varchar(255),
        primary key (id)
    )
create sequence APP_USER_ID_SEQ
As seen for the earlier sequence, this too was created in the default schema. The creation logs are as below:
6485 [main] DEBUG org.hibernate.event.def.DefaultPersistEventListener  - saving 
transient instance
...
6500 [main] DEBUG org.hibernate.SQL  - 
    select
        nextval ('APP_USER_ID_SEQ')
6797 [main] DEBUG org.hibernate.id.SequenceGenerator  - Sequence identifier gene
rated: 1
...
6906 [main] DEBUG org.hibernate.SQL  - 
    insert 
    into
        firstOne.APP_USER
        (NAME, id) 
    values
        (?, ?)
To force it to use the same schema as tables, I made the small change:
@SequenceGenerator(sequenceName = "firstOne.APP_USER_ID_SEQ", name = "AppUserIdSequence")
It worked, Hibernate now used the schema specified.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Learning code way blog is providing best @Generated Value code .
    auto id

    ReplyDelete
  3. This was really helpful. Thank you

    ReplyDelete