4

I am seeing exceptions in my project log and I am not being able to reproduce the problem.

This is happening from time to time (not always) when I try to update a Client using Hibernate. It seems based on the info that is present in logs that hibernate is calling a delete method on an update transaction.

Any idea about why is this happening?

Log

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 // Is this because the client has been deleted by hibernate?
    at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:85)
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:70)
    at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:47)
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2707)
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2911) // This is called by hibernate
    at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:189)
    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 com.project.dao.ClientDAO.updatetx(ClientDAO.java:138)
    at com.project.bl.ClientsBL.updateClient(ClientsBL.java:2291) // This is the method I call
    at [other non hibernate code]

ClientDAO

// ...
public class ClientDAO {
    // ...    
    public Object updatetx(Object instance) throws Exception{
        Session session = getSession();
        Transaction tx = session.beginTransaction();
        session.update(instance);
        tx.commit(); // This is line ClientDAO.java:138

        return instance;
    }
    // ...
}

ClientsBL

//..
public class ClientsBL {
    // ...
    public void updateClient(Client client) {
        // ...
        clientDAO.updatetx(client); // This is ClientsBL.java:2291
        // ...
    }
    // ...    
}

EDIT: adding some more mappings and info:

HBM:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.project.model.client.Client" table="CLIENT" dynamic-update="true">
        <id name="clientId" type="java.lang.Long">
            <column name="CLIENT_ID" />
            <generator class="native" />
        </id>

        <property name="countryId" type="java.lang.Long">
            <column name="COUNTRY_ID" />
        </property>

        <property name="name" type="string">
            <column name="NAME" />
        </property>

        <!-- ... many other columns mapped in the same way -->
    </class>
</hibernate-mapping>

Client.java just have fields+getters+setters (no annotations)

Spring:

<bean id="clientsBL"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
        <ref bean="transactionManager" />
    </property>
    <property name="target">
        <ref bean="clientsBLTarget" />
    </property>
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_SUPPORTS,-Exception</prop>
        </props>
    </property>
</bean>

<bean id="clientsBLTarget"
    class="com.project.bl.ClientsBL">
    <property name="clientDAO"><ref bean="clientDAO" /></property>
    <property name="clientDataDAO" ref="clientDataDAO" />
    <!-- ... more DAOs -->
</bean>
sergioFC
  • 5,926
  • 3
  • 40
  • 54
  • Would it be possible for you to add content of Client entity and or full code for updateClient method? – Runcorn Oct 05 '16 at 13:28
  • Could you be trying to update an entity which no longer exists, q.v. [here](http://stackoverflow.com/questions/2743130/hibernate-batch-update-returned-unexpected-row-count-from-update-0-actual-row)? – Tim Biegeleisen Oct 05 '16 at 13:30
  • @TimBiegeleisen I've checked my code and we never use delete over a Client. It seems to me that the client is being deleted during the update, but I am not sure about that – sergioFC Oct 05 '16 at 13:44
  • Do you have any `@OneToMany` or `@ManyToMany` relations in there? – coladict Oct 05 '16 at 16:48
  • @coladict Client table has relations but we don't use that annotations – sergioFC Oct 05 '16 at 17:09
  • If it does have a relation where a child-entity is removed/replaced, that is probably what's scheduling a delete. I think that if you load the child-entities from an external source they get all deleted and replaced with new ones. It's a simpler and less error-prone way to update child-entities. – coladict Oct 05 '16 at 17:15
  • @coladict Are you saying that maybe is not my Client entity but other entity that is being deleted? – sergioFC Oct 06 '16 at 09:21
  • @Runcorn I am not allowed to do that. – sergioFC Oct 06 '16 at 09:22
  • Have you cascade attribute in your mappings? – ARIS Oct 10 '16 at 08:46
  • @ARIS No. I've just edited the question to add more info – sergioFC Oct 10 '16 at 16:19
  • 1
    put a break point of at the constructor of the hibernate class EntityDeleteAction and check the call stack why this delete action is queued. – hunter Oct 12 '16 at 12:16

3 Answers3

1

A couple weeks ago I had the same exception, eventually, I successfully solved it. The exception was exactly like this: unexpected row count from update [0]; actual row count: 0; expected: 1

These are the phases of how I got that exception in my case:

  1. I "grabbed" a bean from IOC container
  2. I persist\saved that bean using hibernate. That means that the bean received an ID and got saved in DB.
  3. I have deleted that bean. That means the bean is not on DB anymore.
  4. I "grabbed" the same bean from IOC container again. Which means I got a bean with an ID, the ID which it got from before when inserted for the first time.
  5. I tried to execute saveOrUpdate on that "grabbed" bean.

The problem here is that an update occurred instead of insert (save), and I received that exception: unexpected row count from update [0]; actual row count: 0; expected: 1

I got it because hibernate thought that he suppose to do an update because it has been already persisted that bean, that's why the error said expected: 1, it expected to have 1 record that inserted at first. but because it has been deleted already it found actual row count: 0.

The solution is quite simple, just before grabbing from IOC container again, just set the ID to null.

Moshe Arad
  • 3,587
  • 4
  • 18
  • 33
0

It is hard to debug this without the entity mappings, but you say you are not allowed to post it, so the answers can only be speculative at best.

Nevertheless, it is possible that Hibernate issues delete statements when updating an entity if the entity has orphanRemoval directives on one-to-one and one-to-many associations. It is not that the updated entity instance is deleted, but the associated orphans (enable SQL logging to check what exactly is being deleted).

As for the StaleStateException you are getting occasionally, it is very likely that this occurs because a concurrent transaction also modifies the same entity instance (and deletes orphans), so the state that Hibernate has in memory is not consistent with the state in database, and the inconsistency is detected on flush. If this is the case, then you have to deal with concurrent updates to the same data (with optimistic and/or pessimistic locks, etc).

Community
  • 1
  • 1
Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • I haven't had time this week to test the answers (note that the error occurrs in production enviroment). I award you the bounty as you have been the first to answer and I think that this points in the right direction. I will update this post if I am able to reproduce the problem or discover something more about the error. – sergioFC Oct 14 '16 at 12:03
0

can u enable debug level logging in hibernate and check if something is being deleted . It may also be CLIENT_ID value is not present in db can u check the same while debugging that before line 138 does it exist.

gladiator
  • 1,249
  • 8
  • 23