Hibernate throws PK violation error - java

I've been using hibernate with jboss 4.2.3 and everything was working, now i migrated the code to Jboss 7.1.1 and suddenly i start getting :
Caused by: org.hibernate.exception.ConstraintViolationException: ORA-00001: unique constraint (OBLICORE.PK_ACE_WORKERS_QUEUE_STATS_ID) violated
Also the generated ID's are negative.
The entity that fails is defined as such:
#Id
#SequenceGenerator(name = "SEQ_ACE_WORKERS_QUEUE_STATS_ID", sequenceName = "SEQ_ACE_WORKERS_QUEUE_STATS_ID", allocationSize = 500)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ACE_WORKERS_QUEUE_STATS_ID")
#Column(name = "ID")
private long Id;
I checked the sequence in Oracle and it seems O.K (Like i said, it worked before with jboss 4.2 and nothing changed on the DB side since the migration).
I tried writing Hibernate query logs but couldn't locate that query and I've also logged the specific call that persist this class and saw that it only get called once.

Check this question: hibernate oracle sequence produces large gap
It must be Hibernate's sequence generator which is defaulting to the Hi/Lo algorithm, and the returned values overflowing. You can try using a hibernate-specific annotation to default to the older behaviour GenericGenerator(name="blah", strategy="sequence"), or set allocationSize=1.
If you are relying on your sequence incrementing by some value larger than 1, you'll have to use a different generator. Or maybe it's enough to set hibernate.id.new_generator_mappings to false, but that is in the scope of a new question.

When we changed Hibernate to use the new generator, I used the following script to fix the sequences:
DECLARE
v NUMBER;
BEGIN
FOR r IN (select sequence_name from user_sequences) LOOP
EXECUTE IMMEDIATE 'ALTER SEQUENCE '|| r.sequence_name ||' INCREMENT BY 50';
EXECUTE IMMEDIATE 'SELECT '|| r.sequence_name ||' .NEXTVAL FROM DUAL' INTO v;
END LOOP;
END;
/
If your allocationSize is 500, you should change the "INCREMENT BY 50" to "INCREMENT BY 500".

If the generated value of id is not so critical in your project try to use #GeneratedValue(strategy = GenerationType.AUTO)
this strategy will generate id avtomatically by incrementing last by one. Hope it will useful for you.

Related

Hibernate Generation Type for SQL Server and Others

I wrote program that uses different databases like sql server, oracle etc. My problem is that I can't handle GenerationType and insert correct row into table. Using GenerationType.AUTO and hibernate.id.new_generator_mappings := false in sql server, my program is able to insert new row into table, but ID is always null, same problem is when GenerationType is IDENTITY.
I tried to add auto-incrementation only for sql server, but Liquibase yells at me that it's not supported for mssql. When I use Sequences for Oracle as well SQL Server my program is trying to get "next value" from generator but it cannot and do infinite loop. Even if I set default value for ID it won't increment this value.
Thats my code :
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "name")
#SequenceGenerator(name = "name", sequenceName = "SEQ", allocationSize = 1)
private Long id;
I would like to be able to add auto-incrementing indices into table and it should work for SQL Server databases and I don't want to use Table strategy for generation because it needs additional table in db.
Problem solved. I add condition in Liquibase xml file that checks whether db is mssql type and if it's true script drops ID column and adds it with IDENTITY(1,1) option.
The only problem is that now I have to switch aforementioned "hibernate.id.new_generator_mappings" setting.

How force hibernate to sync sequences?

I try to prepare an integration test with test data. I read insert queries from an external file and execute them as native queries. After the insertions I execute select setval('vlan_id_seq', 2000, true );. Here is the entity ID definition:
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = IDENTITY)
private Integer id;
When I try tor persist a new entry, I got a Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "vlan_pkey"
Detail: Key (id)=(1) already exists. exception. The ID of the sequence is 2000. The column definition is done by the serial macro and is id integer NOT NULL DEFAULT nextval('vlan_id_seq'::regclass).
I executed the native queries in a user transaction, so all test entries are stored in the postgresql data base, but it seems that hibernate not sync the sequence. The entityManager.flush(); also didn't force a sequence synchronisation. It seems that hibernate did not use sequences with #GeneratedValue(strategy = IDENTITY). I use a XA-Datasource and wildfly 13.
I tested now an other initialisation method. I defined a SQL data script (I generated the script with Jailer) in the persitence.xml (javax.persistence.sql-load-script-source) and end the script with select pg_catalog.setval('vlan_id_seq', (SELECT max(id) FROM vlan), true );. I set a breakpoint before the first persist command, check the sequence in the postgresql db, the sequence has the max id value 16. Now persisting works and the entry has the id 17. The scripts are executed before the entity manager is started and hibernate read the the updated sequences while starting. But this solution did not answer my question.
Is there a possibility that hibernate reread the sequences to use the nextval value?
if the strategy is Identity this means hibernate will create a sequence table and fetch the IDs from it, by using native sql you are just inserting your own values without updating that table so you have TWO solutions
Insert using hibernate itself which will be fairly easy, in your
integration test inject your DAOs and let hibernate do the insertion
for you which is recommended so you do not need to rehandle what
hibernate already handled
Update the sequence table whenever you do the insert by increment the
value which I do not recommend.

Oracle sequence returns different value when issued from java hibernate vs sql developer

I am running into this really weird issue where an oracle sequence returns very different values when issued from java/Hibernate vs SqlDeveloper tool.
#SequenceGenerator(name = "PARAM_ID_SEQUENCE", initialValue = 10, allocationSize = 30, sequenceName = "PARAM_ID_SEQUENCE")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PARAM_ID_SEQUENCE")
#Column(name = "PARAMETER_ID")
The above returns 1177248345. I turned the loglevel to trace to see the actual query being issued and it is: select SPS_PARAM_ID_SEQUENCE.nextval from dual.
Now I issue the very same query against the same sequence from sql developer tool and it returns: 39241615 which is 2 orders of magnitude lesser! Also, this is the accurate value I would expect.
CREATED 03-OCT-14
LAST_DDL_TIME 25-JAN-18
SEQUENCE_OWNER API
SEQUENCE_NAME PARAM_ID_SEQUENCE
MIN_VALUE 1
MAX_VALUE 9999999999999999999999999999
INCREMENT_BY 1
CYCLE_FLAG N
ORDER_FLAG N
CACHE_SIZE 20
LAST_NUMBER 39241624
PARTITION_COUNT
SESSION_FLAG N
KEEP_VALUE N
I confirmed that both are issuing requests on the same environment against the same database schema etc, but for some reason Hibernate gets a much higher value. Has anyone faced a similar issue. Is hibernate "padding" the sequence somehow?

Hibernate sequence nextVal resolved but not used (Oracle)

Hibernate is not assigning objects ids from the Oracle sequence as expected. Here's what I see in the Hibernate debug logs.
DEBUG o.h.SQL:92 - select MY_SEQ.nextval from dual
DEBUG o.h.i.e.SequenceStructure:102 - Sequence value obtained: 22643
DEBUG o.h.r.j.i.ResourceRegistryStandardImpl:73 - HHH000387: ResultSet's statement was not registered
DEBUG o.h.e.i.AbstractSaveEventListener:118 - Generated identifier: 22594, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
The first "sequence value obtained" is correct, 22643 comes right from MY_SEQ.nextVal as it says. But then the "generated identifier" that gets used is 22594. What gives?
I've tried tweaking the generator strategy to no avail.
#Id
#SequenceGenerator(name = "generator", sequenceName = "MY_SEQ")
#GeneratedValue(generator = "generator", strategy = GenerationType.SEQUENCE)
#Column(name = "MY_ID", nullable = false, precision = 6, scale = 0)
private Integer id;
I can include my Spring Hibernate context configuration if that'll help. I don't see anything in there that looks obviously relevant.
Hibernate with Oracle sequence doesn't use it is very probably related, but that deals with gaps while the id I get is less than the sequence value obtained.
PS: Other tickets discuss sequence generator strategies that optimize efficiency. A single record of this data is inserted once a month or so, and only from this class. So, efficiency isn't a concern here.
Update 1
I am able to recreate this in HSQLDB in Oracle emulation mode too. So it's surely a Hibernate issue.
Update 2
The offset is always exactly 49. The example above correctly fetched 22643 from the sequence, but then resolved 22594 as the next value.
22643-22594=49
In another example, the next sequence value was actually 4, and Hibernate gave me -45.
4-(-45)=49
Update 3
Subsequent inserts do not call the Oracle sequence's nextVal. I suspect JPA/Hibernate is trying to fetch ids in bulk upfront for efficiency.
DEBUG o.h.SQL:92 - select MY_SEQ.nextval from dual
DEBUG o.h.i.e.SequenceStructure:102 - Sequence value obtained: 22643
DEBUG o.h.r.j.i.ResourceRegistryStandardImpl:73 - HHH000387: ResultSet's statement was not registered
DEBUG o.h.e.i.AbstractSaveEventListener:118 - Generated identifier: 22594, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
...
DEBUG o.h.e.i.AbstractSaveEventListener:118 - Generated identifier: 22595, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
As I mentioned in my 3rd update, JPA was "fetching 50 ids" from the sequence up front and counting through them in memory for efficiency.
This behavior is specified by javax.persistence.SequenceGenerator.allocationSize which defaults to 50.
(Optional) The amount to increment by when allocating sequence numbers from the sequence.
This isn't at all intuitive to me, or others, since my Oracle database sequence is supposed to define this behavior and 50 isn't a standard default there.
The quick and dirty solution was to specify allocationSize=1:
#SequenceGenerator(name = "generator", sequenceName = "MY_SEQ",
allocationSize = 1)
Now the Oracle sequence is incremented for every insert.

Hibernate: #GeneratedValue(strategy = GenerationType

I am using DB2 for my application. I run some insertion script after creating database. That insertion script generates records in table with id's given in insertion script.
Suppose for abc table insertion script creates a record with id = 3. As id’s are set to auto generated in hibernate so while saving third record from application I got exception.
Caused by: com.ibm.websphere.ce.cm.DuplicateKeyException: One or
more values in the INSERT statement, UPDATE statement, or foreign
key update caused by a DELETE statement are not valid
because the primary key, unique constraint or unique
index identified by "1" constrains table
I am using #GeneratedValue(strategy = GenerationType.AUTO)
What strategy = GenerationType I should use to overcome this problem.
There are issues with certain Databases and Hibernate when you use GenerationType.IDENTITY. Try using a sequence and explicitlly configure everything for it:
#Id
#SequenceGenerator(name = "DEPARTMENT_ID_GENERATOR", sequenceName="department_sequence", allocationSize=100)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "DEPARTMENT_ID_GENERATOR")
#Column(unique = true, nullable = false)
protected Long id;
For DB2 #GeneratedValue(strategy = GenerationType.IDENTITY) should work correctly.
If ids are provided in file then you don't need #GeneratedValue at all as there is no id to generate. And make sure to clean database as #SjB suggested.
Also, without knowing much about DB2, the error message suggests that there may be other violation than just duplicate id on insert. Are there any foreign keys involved?
Nothing works except this query.
alter table TABLE_NAME alter column ID set GENERATED BY DEFAULT RESTART WITH 10000;
DB2 should choose available ID itself but not doing so.

Categories