Disable hibernate HiLo Sequence generation - java

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.

Related

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.

How to make Hibernate to use SequenceHiLoGenerator for JPA GenerationType.AUTO on Oracle?

I have a table with id like below, but hibernate uses org.hibernate.id.SequenceGenerator instead of SequenceHiLoGenerator for GenerationType.AUTO, how can I tell hibernate to use SequenceHiLoGenerator?
#Id
#SequenceGenerator(name="admin_seq", sequenceName="unique_id")
#GeneratedValue(strategy=GenerationType.AUTO, generator="admin_seq")
private Long id
If I use GenerationType.SEQUENCE, hibernate will use SequenceHiLoGenerator, but I need to use GenerationType.AUTO for compatibility with MySQL.
I have tried using #GenericGenerator, it works for Oracle but will be complained by MySQL: org.hibernate.dialect.MySQLDialect does not support sequences.
#GenericGenerator(name = "admin_seq", strategy = "org.hibernate.id.SequenceHiLoGenerator",
parameters = {
#Parameter(name = "sequence", value = "unique_id"),
#Parameter(name = "max_lo", value = "50") })
#GeneratedValue(strategy=GenerationType.AUTO, generator="admin_seq")
private Long id
I also tried using SequenceStyleGenerator by setting hibernate.id.new_generator_mappings=true in hibernate properties. It doesn't work either.
If you set hibernate.id.new_generator_mappings=true which uses SequenceStyleGenerator, it would work with Oracle. We have similar configuration in our project which works fine.
If you want to achieve bulk id retrieval(like 50 each time) to speed up the persist/save, the quirk here is you need to set allocationSize to 50 and also set your sequence Increment By to 50. 50 here is just a random number I choose, if you have massive persist, you can assign larger number. The most important thing here is the allocationSize in code and the Increment By in Database should MATCH.
The Oracle sql is something like
ALTER SEQUENCE YOUR_SEQUENCE_NAE INCREMENT BY 50;
The JPA entity ID field is like:
#SequenceGenerator(name = "YOUR_ID_GEN", sequenceName = "SEQ_YOUR_ID", allocationSize=50)
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "YOUR_ID_GEN")
#Column(name = "YOUR_ID")
public Long getYourId() {
return this.yourId;
}
strategy = GenerationType.AUTO should work against MySQL with an identity column even though you've configured a sequence too. The sequencegenerator will be used when running against Oracle, but ignored when running against MySQL.
In your persistence.xml you should also switch your hibernate.dialect property between the correct values for a Oracle dialect and a MySQL dialect.

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.

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

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;

GeneratedValue in Postgres

I have my entity class mapped like below:
#Entity
#Audited
#Table(name="messages_locale")
public class Locale {
#Id
#GeneratedValue
#Getter #Setter //Project Lombok's annotations, equal to generated getter and setter method
private int id;
(...)
I create clean new database ,and properties:
< prop key="hibernate.hbm2ddl.auto" >create < /prop>
WHY THE HELL (Sorry, almost two days wasted on this bug) after created database, i got a sequence in my postgres db?:
CREATE SEQUENCE hibernate_sequence
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 2
CACHE 1;
ALTER TABLE hibernate_sequence
OWNER TO postgres;
I dont want to have a sequence, I want to have just auto increment auto generated values..
I think the accepted answer from Petar is not correct, or not correct any longer. The auto-increment in Postgres is handled through SERIAL pseudo type, that’s correct. However, the mapping that Petar gives will result in the following DDL generated by Hibernate 5.1:
CREATE SEQUENCE users_id_seq START 1 INCREMENT 50;
CREATE TABLE … (
id INT8 NOT NULL,
…
);
This is not using SERIAL, but a Hibernate managed sequence. It is not owned by the table and no default value has been set. Of course, DDL generation is a feature that many people do not use in production (but many take the generated code as a template).
If you hand-write your DDL and actually used SERIAL, then using GenerationType.SEQUENCE may even conflict with the database behaviour. The correct way to map Hibernate with Postgres’ preferred ID strategy is using GenerationType.IDENTITY. Incidentally, the code is also much shorter and more readable:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
In PostgreSQL auto-increment is handled using the SERIAL pseudo type. You use this type when you execute CREATE TABLE.
Now to the point - this SERIAL pseudo type creates a sequence.
Autoincrement in PostgreSQL is handled using the created sequence. The default value of the id column becomes - nextval('your_sequence_name').
In Hibernate for an User entity:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "users_seq_gen")
#SequenceGenerator(name = "users_seq_gen", sequenceName = "users_id_seq")
public Long getId() {
return id;
}
Read here:
http://www.postgresql.org/docs/8.4/static/datatype-numeric.html#DATATYPE-SERIAL
http://www.neilconway.org/docs/sequences/

Categories