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.
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:
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:
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 :
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_sequenceAs 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: 1The 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_SEQAs 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.
This comment has been removed by the author.
ReplyDeleteLearning code way blog is providing best @Generated Value code .
ReplyDeleteauto id
This was really helpful. Thank you
ReplyDelete