0

I have web application using Hibernate deployed in 3 load balanced Tomcats

and I am frequently getting the following exception

org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:92)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:87)
at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:222)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2224)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2660)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:56)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:234)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at com.googlecode.s2hibernate.struts2.plugin.interceptors.SessionTransactionInjectorInterceptor.intercept(SessionTransactionInjectorInterceptor.java:181)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:488)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129)
at com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:197)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1770)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Caused by: java.sql.BatchUpdateException: Duplicate entry '145985' for key 'PRIMARY' at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1666) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1082) at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723) at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246) ... 38 more

And I used the following configuration

@Id
@GenericGenerator(name = "generator", strategy = "increment")
@GeneratedValue(generator = "generator")
@Basic(optional = false)
@Column(name = "address_id", nullable = false)
private Long addressId;
Rocko
  • 3
  • 2

1 Answers1

2

IncrementGenerator is not cluster safe, as documented in the source. It works by reading max id value for the first time and keep increment it in memory. In your case, suppose, at the start, the max value is 10. The IncrementGenerator at 3 nodes may read the value as 10 and assign 11 as the id for the instances created in each node.

Always rely on your database id generation mechanism to be cluster safe.

Adisesha
  • 5,200
  • 1
  • 32
  • 43
  • how to make sure that db generates the auto increment id in hibernate? if we pass null, hibernate passes null object as the value to the db. – Rocko Apr 02 '13 at 18:14
  • It depends on your db..for oracle see http://stackoverflow.com/questions/2384420/how-is-my-id-being-generated-with-jpa-using-hibernate-with-the-oracle-10g-dialec – Adisesha Apr 02 '13 at 19:13
  • In MySql, you can use AUTO_INCREMENT attribute for id columns,http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html. Annotate addressId, with @Id @GeneratedValue(strategy=GenerationType.AUTO) – Adisesha Apr 04 '13 at 05:57
  • Thanks a lot. **GenerationType.AUTO** does the trick what I was looking for. – Rocko Apr 04 '13 at 14:05