0

I'm doing a batch processing of records from file in to MySQL through Hibernate. I'm trying to iterate over the records and save them, up on ConstraintViolationException i'm trying to update the record in catch clause. Some how this fails with AssertionFailure Exception.

I'm bounded to use Sessions rather than StatelessSessions.

try {
  System.out.println("Inserting "+key);
  session.save(mud);
} catch(HibernateException cve) {
    cve.printStackTrace();
    //log.error("Failed insert, record already exists: "+key);
    System.out.println("Failed insert, record already exists: "+key);
    List res = session.createQuery("from UserData as ud where ud.taskId = "+taskId+" and ud.userId= "+userId)
        .list();
    System.out.println("Query successfull");
    if (!res.isEmpty()) {
          mud.setId( ((UserData) res.get(0)).getId() );
          session.save(mud);
          continue;
}

}

Here's the StackTrace:

Inserting 463531145008722
org.hibernate.exception.ConstraintViolationException: could not insert: [com.test.www.UserData]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2345)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2852)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:713)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:701)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:697)
at com.test.www.CSVToDB.LoadCSVToDB_statelessNoTransaction(CSVToDB.java:92)
at com.test.www.CSVToDB.run(CSVToDB.java:52)
at com.test.www.CSVToDB.main(CSVToDB.java:175)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '463531-145008722' for key 'taskId'
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1041)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4190)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4122)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2818)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2157)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2460)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2377)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2361)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
... 18 more
Failed insert, record already exists: 463531145008722
org.hibernate.AssertionFailure: null id in com.test.www.UserData entry (don't flush the Session after an exception occurs)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:82)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:190)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:147)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at com.test.www.CSVToDB.LoadCSVToDB_statelessNoTransaction(CSVToDB.java:98)
at com.test.www.CSVToDB.run(CSVToDB.java:52)
at com.test.www.CSVToDB.main(CSVToDB.java:175)
Aryan
  • 61
  • 2
  • 7
  • Is there a particular reason for you to try to insert first? How about if you follow (1) Query the database looking for the record you want. (2) If exists; then save mud...? – Rafa Aug 07 '13 at 12:36
  • yes, I need the record to be saved on to database in any case, just that if the record already exists I would need to do an update. Also since the size of the records to be saved is huge (~50 Million) query then insert is taking lot of time and db load, also updates are relatively rare. – Aryan Aug 07 '13 at 12:55

1 Answers1

0

Looking better (and checking Hibernate code) seems a problem during query.list() (in stacktrace Query successfull is missing) and automatic flush running before query execution. Try change flushMode to COMMIT or do a session.flush() before query.

Do you look at spring-batch for this kind of job?

Luca Basso Ricci
  • 17,829
  • 2
  • 47
  • 69
  • from [this](http://stackoverflow.com/questions/6443672/hibernate-saveorupdate-behavior) Hibernate would always save `mud` because thats a new object being created from rest of the code. – Aryan Aug 07 '13 at 11:05
  • I don't understand very well: you are creating `mud` items with a `new`, right? Is `key` the @Id of `mud` being save? In this case you can do a `mud.setId(key)` than perform a `mud = merge(mud)`. You have to reattach object before save() an transient object (Is mud @Id manual or automatically generated by Hibernate)? – Luca Basso Ricci Aug 07 '13 at 11:23
  • @Id is automatically generated by hibernate. Basically i'm creating a new object, trying to insert it in to DB and if the insert fails due to record already being in the database(Which may or maynot be created by current hibernate session), i'm retrieving the record and updating it with current object data. – Aryan Aug 07 '13 at 11:57
  • 1
    Last try, I have not other clue. Looking better (and checking Hibernate code) seems a problem during `query.list()` (in stacktrace `Query successfull` is missing) and automatic flush running before query execution. Try change flushMode to COMMIT or do a session.flush() before query. – Luca Basso Ricci Aug 07 '13 at 12:25
  • It worked when I changed the flush mode to COMMIT ! Thanks :) – Aryan Aug 07 '13 at 12:49
  • you welcome. I change answer according to last comment, for posterity! :) – Luca Basso Ricci Aug 07 '13 at 13:01