Java – org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1

hibernatejavaMySQLstalestateexception

Sometimes when persisting an obj, one of its field is too large to fit into the db field, resulting in a data truncation exception. In the following code, I attempt to catch the DataException and simply empty out the field, and the resave. However I get an exception when resaving. Why does the Batch update exception occur and how do I get around it?


 public static void save(Object obj) throws Exception{
        try{
            beginTransaction();
            getSession().save(obj);
            commitTransaction();

        }catch(Exception e){
            e.printStackTrace();
            rollbackTransaction();
            throw e;
        }finally{
            closeSession(); //not needed, session obtained from sf.getCurrentSession() will auto close
        }
    }   
 public static void saveXXX(XXX rec){

        try {
            save(rec);
        } catch (org.hibernate.exception.DataException e) {
            e.printStackTrace();

            saveXXX(rec, e); //causes an exception      
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
    private static void saveXXX(WhoisRecord rec, DataException e) {
        rec.setField(""); //empty out the problem field
        saveXXX(rec);

Exception:

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
    at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:90)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)
    at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)
    at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2382)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
.
.
.

Best Answer

I'm no expert on this, but I think I just had the same problem but in the opposite direction.

It looks like what's happening is that you try to save the record, and Hibernate throws that data truncation exception, meaning it saved something but not all of what you wanted. So you catch that exception, and try to roll back the transaction. But this isn't always guaranteed to succeed (from what I see on Hibernate save() and transaction rollback), so the saved data could still be there. Let's assume it is. Next you alter your record, and try to save it again.

But since the data is still there, calling save won't do anything, as in that case it should be an update. So when you try to commit that transaction, Hibernate knows that you want to save the 1 record but it succeeds in saving 0, hence the error.

Try changing getSession().save(obj); to getSession().saveOrUpdate(obj);. That should save the record when it doesn't exist and update it (to not have the overlarge field) when it does.

Related Topic