Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)
.
.
.
like image 214
user121196 Avatar asked Feb 23 '11 03:02

user121196


2 Answers

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.

like image 79
Hammer Bro. Avatar answered Oct 12 '22 23:10

Hammer Bro.


I got this error because I had the wrong generator of the key in the class mapping, and then I did an insert first and an update later in the same transaction.

The key column was defined as autoincrement (in MySQL), and with this mapping

<id name="tableId" type="long" access="field">
   <column name="tableId" />
   <generator class="assigned" />
</id>

I got a StaleStateException, but when I corrected the entry to

<id name="tableId" type="long" access="field">
   <column name="tableId" />
   <generator class="native" />
</id>

then it worked well without problems.

like image 29
Johanna Avatar answered Oct 12 '22 22:10

Johanna