繁体   English   中英

为什么在更新事务期间hibernate调用delete?

[英]Why is hibernate calling delete during an update transaction?

我在项目日志中看到异常,我无法重现问题。

当我尝试使用Hibernate更新客户端时,这种情况时有发生(并非总是如此)。 它看起来基于hibernate在更新事务上调用delete方法的日志中存在的信息。

知道为什么会这样吗?

日志

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
        // ...
    }
    // ...    
}

编辑 :添加一些映射和信息:

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只有字段+ getter + setters(没有注释)

弹簧:

<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>

几周前我遇到了同样的例外,最终我成功地解决了它。 例外情况与此类似: unexpected row count from update [0]; actual row count: 0; expected: 1 unexpected row count from update [0]; actual row count: 0; expected: 1

这些是我在我的案例中得到异常的阶段:

  1. 我从IOC容器“抓住”了一个豆子
  2. 我坚持使用hibernate保存那个bean。 这意味着bean收到了一个ID并保存在DB中。
  3. 我删除了那个bean。 这意味着bean不再在DB上了。
  4. 我再次从IOC容器“抓住”了同样的豆子。 这意味着我得到了一个带有ID的bean,这是第一次插入之前从中获得的ID。
  5. 我试图在“抓住”的bean上执行saveOrUpdate

这里的问题是发生了更新而不是插入(保存),我收到了异常: unexpected row count from update [0]; actual row count: 0; expected: 1 unexpected row count from update [0]; actual row count: 0; expected: 1

我得到它是因为hibernate认为他想要做一个更新,因为它已经持有那个bean,这就是为什么错误说expected: 1 ,它预计首先插入1条记录。 但因为它已被删除,它发现actual row count: 0

解决方案非常简单,就在再次从IOC容器中获取之前,只需将ID设置为null即可。

没有实体映射很难调试它,但是你说不允许你发布它,所以答案只能是最好的推测。

然而,如果实体在一对一和一对多关联上具有orphanRemoval指令,则在更新实体时Hibernate可能会发出delete语句。 这不是删除更新的实体实例,而是关联的孤立( 启用S​​QL日志以检查确切删除的内容)。

对于偶尔会出现的StaleStateException ,很可能会发生这种情况,因为并发事务也修改了同一个实体实例(并删除了孤儿),因此Hibernate在内存中的状态与数据库中的状态不一致,在冲洗时检测到不一致。 如果是这种情况,那么您必须处理对相同数据的并发更新(使用乐观和/或悲观锁等)。

你可以在hibernate中启用调试级别日志记录并检查是否正在删除某些内容。 它也可能是在DB2中不存在的CLIENT_ID值可以在调试之前检查相同的内容,然后在第138行存在之前。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM