JPA/Ebean - force #Id to strictly increment by +1 with PostgreSQL - java

I have the following Model:
public class Parameter extends Model {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public long id;
}
The records created by save() look like this:
play=> select id from parameter;
id
----
1
2
3
4
5
21
(6 rows)
Is there a way that I can tell JPA to always increment the id by exactly one, instead of randomly jumping to 21?

What you are observing (jump to 21) is likely to be an implmentation detail of Ebean prior to 4.0.5. Ebean is using a 'fetch ahead' mechanism on the sequence. After 4.0.5 Ebean switched to use Postgres SERIAL by default (so by default you won't see this with Ebean/Postgres after 4.0.5). Refer: https://github.com/ebean-orm/avaje-ebeanorm/issues/97
That all said - 'incrementing EXACTLY by 1' is something you generally want to avoid as it becomes a concurrency issue (avoid making the autoincrement ID transactional as that introduces contention). When you need 'increment exactly by one' semantics (like cheque numbers etc) then you can look to create in batch in advance.

You should be able to achieve this by using #TableGenerator and allocationSize=1. An example code something like the following. You need to create a separate table to store the PK, additional work, but more portable than #GeneratedValue.
#TableGenerator(name="MAIN_PK_GEN", table="pk_gen", pkColumnName="GEN_NAME", valueColumnName="GEN_VALUE", pkColumnValue="MAIN_PK_GEN", allocationSize=1)
#Id #GeneratedValue(strategy=GenerationType.TABLE, generator="MAIN_PK_GEN" )
#Basic(optional = false)
#Column(name = "PK")
private Integer pk;
(But using allocationSize=1 may not be efficient)
See this tutorial for step by step explanation.

If you are using Oracle don't forget to add SequenceGenerator with an allocationSize of 1 :
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mysequence")
#SequenceGenerator(name = "mysequence", sequenceName = "mysequence", allocationSize = 1)
private Long id;

Related

Hibernate having issues with sequence object - unable to call next val

I am using hibernate entity - and sequence generator with it.
My database is Oracle 12c.
In my sequence generator - it fetches value which is already present in table.
I tried looking out for issue - found one simmilar thread
Hibernate sequence nextVal resolved but not used (Oracle)
But still it did not help . The issue am facing is - it works some times and it does not work some times
Below is my code snippet -
#Entity
#Table(name="TABLE_NAME", schema = "SCHEMA")
#SequenceGenerator(name="TABLE_ID_SEQ_GEN", sequenceName="SCHEMA.TABLE_ID_SEQ",allocationSize=1)
public class ImportTransactionDataEntity {
#Id
#Column(name="TABLE_ID",unique=true,nullable=false)
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="TABLE_ID_SEQ_GEN" )
private int IDColumnPk;
ANy help is appreciated , thank you :)
According to Oracle documentation, the #SequenceGenerator should be added to the field, not to the class:
https://docs.oracle.com/cd/E16439_01/doc.1013/e13981/cmp30cfg001.htm#BCGGHADG
so something like:
#Entity
#Table(name="TABLE_NAME", schema = "SCHEMA")
public class ImportTransactionDataEntity {
#Id
#Column(name="TABLE_ID",unique=true,nullable=false)
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="TABLE_ID_SEQ_GEN" )
#SequenceGenerator(name="TABLE_ID_SEQ_GEN", sequenceName="SCHEMA.TABLE_ID_SEQ",allocationSize=1)
private int IDColumnPk;
This works for me.
try this
#Entity
#Table(name="TABLE_NAME")
#SequenceGenerator(name="TABLE_ID_SEQ_GEN",sequenceName="TABLE_ID_SEQ",allocationSize=1)
public class ImportTransactionDataEntity {
#Id
#Column(name="TABLE_ID",unique=true,nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO,generator="TABLE_ID_SEQ_GEN" )
private int IDColumnPk;
it is stored in you database like this the last nummber is the last id used so dont worry about loosing count cause the database does that for you
well finally - i had come to a solution that i was already using oracle 12 C - decide to go with Identity column on the table it self .
NOTE - but the identity column is not available before Oracle 12c .
I ended up getting better performance also with some fraction , so this work around was sigh of relief for me
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "TABLE_ID", updatable = false, nullable = false)
private int IDColumnPk;

HIbernate do not use sequence for PostgreSQL

I'm stuck in some problem: I need to use sequences in PostgreSQL for generating ids. But when I save new object in table, it says that id is null
org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
I use these annotations:
#SequenceGenerator(name = "fooGen", sequenceName = "FOO_SEQ", allocationSize = 1)
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "fooGen")
#Column(columnDefinition = "numeric")
private BigInteger id;
And this worked fo Oracle. I've watched a lot of questions, but most used GenerationType.AUTO or GenerationType.IDENTITY, and solution was to use GenerationType.SEQUENCE. But I'm already using it.
I got this exception when trying to save my entity with repository method
fooRepository.saveAndFlush(entity);
My database is PostgreSQL 9.6.1.
I use
org.hibernate.dialect.PostgreSQL9Dialect
Sequence exists, I checked it. And hibernate.hbm2ddl.auto=validate would give me exception if it wouldn't be there.
Please, help me, where did I make a mistake?
I am using database schema:
<prop key="hibernate.default_schema">${jdbc.postgresql.schema}</prop>
maybe, this cause some problems?
Thanks in advance
Try to change type for id to Long like
#SequenceGenerator(name = "fooGen", sequenceName = "FOO_SEQ", allocationSize = 1)
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "fooGen")
#Column(columnDefinition = "numeric")
private Long id;
This table has many-to-many relation, and table that connected two entities has its own id field. Hibernate had no mapped Java class for this table, and didn't set this id. And solution was to remove this field.

Which GenerationType is best among AUTO,IDENTITY & TABLE(or Any other best approch) using Hibernate persistence provider?

In my project we are using Oracle and we want to give support for MYSQL also. Oracle have sequence support but MYSQL don't have. which GenerationType is good if we want to support ORACLE and MYSQL with same code base using Hibernate persistence provider among AUTO,IDENTITY & TABLE(or Any other way)?, can any one give brief description about these please?
Ex:
Class POJO{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
------
#GeneratedValue(strategy = GenerationType.IDENTITY)
-----
#GeneratedValue(strategy = GenerationType.TABLE)
------
(or Any other best approch?)
}
You can use
#GeneratedValue(generator = GenerationType.TABLE)
It will work for both Oracle and mySql
Since MySQL supports auto_increment use GenerationType.AUTO for its corresponding POJOs.
For the POJOs for Oracle database you could create a sequence for each and use it in your POJOs as illustrated below.
Sequence creation
CREATE SEQUENCE MY_SEQ
INCREMENT BY 1
START WITH 1
NOMAXVALUE
NOCYCLE
NOCACHE;
Generation type
I suppose the primary key is labeled ID in your Oracle table.
#Id
#GeneratedValue(generator = "mySeq")
#SequenceGenerator(name = "mySeq", sequenceName = "MY_SEQ", allocationSize = 1)
#Basic(optional = false)
#NotNull
#Column(name = "ID")
private Long id;
You may want to look into configuring all the database-dependant stuff in an xml configuration file. I haven't used xml files to configure hibernate for years and I've never mixed it with annotations. But the way I understand it: Your xml configuration will overwrite this specific configuration from your annotations in your POJO.
So you could leave your POJO with your oracle-specific ID Generator, and in case you deploy it for a MySQL, you would need to add an xml configuration with your MySQL-specific ID Generators.
I can't give you any details on this though. sorry.

hibernate - how to set auto increment in both mysql and oracle databases?

I'm using hibernate with a MySQL database in my spring MVC project. I have used the #GeneratedValue annotation to set auto-incremenet on my id fields. So all my entities have this piece of code and everything is working as expected:
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
At this time, I want to switch to an Oracle database. Now, I have two questions here:
1. What's the best solution to set auto-increment field in oracle? I used this code, but is not working:
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "id_Sequence")
#SequenceGenerator(name="id_Sequence", allocationSize=1)
2(More important question). Is there any way to use a unique annotation to set auto-increment that will work for both MySQL and Oracle?
1:
If you define your own generator, your have to use the generator attribute in #GeneratedValue. And if you have created your own sequence you have to define the name with sequenceName otherwise hibernate will create one for you.
#SequenceGenerator(name="some_gen", sequenceName="Emp_Seq")
#GeneratedValue(generator="some_gen")
2:
The most flexible (and portable) way is to use the TABLE strategy
#GeneratedValue(strategy=GenerationType.TABLE)
or more explicit
#GeneratedValue(generator="some_gen")
#TableGenerator(name="some_gen",
table="ID_GEN",
pkColumnName="GEN_NAME",
valueColumnName="GEN_VAL")
This will generate (if schema generation is enabled) a table ID_GEN with the columns GEN_NAME, GEN_VALUE, if schema generation is not available you have to create this table on your own.
You find more complete information from hibernate docs here: http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch05.html#mapping-declaration-id-generator

Disable hibernate HiLo Sequence generation

I'm working with Hibernate 4.2.x and I want to disable the HiLo sequence generation - go to the DB (oracle) every time.
I added this row to the persistance.xml:
<property name="hibernate.id.new_generator_mappings" value="true"/>
And my entity looks like this:
#Entity
#Table(name = "MY_TABLE")
#SequenceGenerator(name = "generator", sequenceName = "MY_SEQ", initialValue = 1, allocationSize = 1)
public class MyEntity {
private long id;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator")
public Long getId()
{
return id;
}
}
For some reason I still getting HiLo behavior - ids created far away from each other.
Looked on some questions (here and here for example), but didn't find anything helpful. More ever, I couldn't find where to configure which Optimizer to use.
Being not too familiar with hibernate, my guess is that it's using an Oracle database-sequence as source. One of the features of Oracle sequences is the sequence cache. check in the definition of the sequence if the cache size is set (default = 20). I know that after a restart of the database the cache is purged anyway, so that's when you lose consecutive numbers.
Modify the sequence with the command:
alter sequence MY_SEQ nocache;
Keep in mind that OLAP performance may deteriorate when sequences are not cached.

Categories