Using oracle auto increment trigger with hibernate
-
28-05-2021 - |
Question
I am using hibernate to do mapping from my java class to oracle tables. For my primary key id, i am using
<generator class="increment"></generator>
Because my code needs to be run on two machines, i get the following exception very often:
java.util.concurrent.ExecutionException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at jobsrc.BasicDaoImpl.save(BasicDaoImpl.java:65)
Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint (DB.SYS_C0011343) violated
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10700)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 18 more
That's because I am using hibernate's increment, it tries to again the latest number in memory. Could anyone can show how can i use oracle's auto_increment in hibernate? I add the trigger in database directly, but hibernate crashes when it trying to call saveOrUpdate:
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at jobsrc.BasicDaoImpl.saveOrUpdate(BasicDaoImpl.java:37)
Caused by: java.sql.BatchUpdateException: No more data to read from socket
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10700)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 13 more
Thank you very much!!!!!!!!!
La solution
Oracle doesn't have an auto_increment type. You should use a sequence generator, as shown and explained in this section of the Hibernate reference manual.
Autres conseils
Hibernate actually can read back the value created by a trigger. There are actually 2 ways you can do this:
- Use the org.hibernate.id.SequenceIdentityGenerator generator. This works on the JDBC getGeneratedKeys feature, specifically the form allowing to name the columns to be returned. This is highly non-portable across databases. And, in my experience, it is even non-portable across Oracle driver versions (although I have not tried for many years)
- Use the org.hibernate.id.SelectGenerator generator. This one works by selecting the identifier column(s) from the just-inserted row using the column(s) of a property defined as unique. You either (a) configure the generator to tell it the unique property, or (b) if you happen to use @NaturalId/ mapping, that is used automatically.
However, "post insert" identifier generators (such as these two as well as IDENTITY generation) often open up a whole new can of worms in terms of impl details for your application. I strongly recommend against using "post insert" identifier generators. You are much better off, IMO, using the sequence generator as discussed in the earlier answer