我在项目日志中看到异常,我无法重现问题。
当我尝试使用Hibernate更新客户端时,这种情况时有发生(并非总是如此)。 它似乎基于日志中存在的信息 hibernate在更新事务上调用删除方法。
有关为什么会发生这种情况的任何想法?
日志
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>
答案 0 :(得分:1)
几周前,我有同样的例外,最终,我成功地解决了它。例外情况如下:unexpected row count from update [0]; actual row count: 0; expected: 1
这些是我在我的案例中如何得到该异常的阶段:
saveOrUpdate
,然后#34;抓住&#34;豆。这里的问题是更新发生而不是插入(保存),我收到了异常:unexpected row count from update [0]; actual row count: 0; expected: 1
我得到了它,因为hibernate认为他想要做一个更新,因为它已经持久化了bean,这就是为什么错误说expected: 1
,它预计会有一条记录首先插入。但由于它已被删除,因此发现actual row count: 0
。
解决方案很简单,就在再次从IOC容器中抓取之前,只需将ID设置为null。
答案 1 :(得分:0)
如果没有实体映射,很难调试它,但是你说不允许发布它,所以答案只能是推测性的。
然而,如果实体在一对一和一对多关联上具有delete
指令,则更新实体时Hibernate可能会发出orphanRemoval
语句。这不是删除更新的实体实例,而是关联的孤儿(enable SQL logging来检查确切删除的内容)。
对于偶尔会遇到的StaleStateException
,很可能会发生这种情况,因为并发事务也会修改同一个实体实例(并删除孤儿),因此Hibernate在内存中的状态不一致与数据库中的状态,并在flush上检测到不一致。如果是这种情况,那么您必须处理相同数据的并发更新(使用乐观和/或悲观锁等)。
答案 2 :(得分:0)
可以在hibernate中启用调试级别日志记录并检查是否正在删除某些内容。 它也可能是db中不存在的CLIENT_ID值,你可以在第138行调试之前检查相同的内容。