`
风云无浪
  • 浏览: 14958 次
社区版块
存档分类
最新评论

Hibernate数据delete时容易忽略的问题

阅读更多
在主线程通过hibernate的find查询到数据后,把list里数据分别加入到新的list中,然后给子线程处理,子线程在执行getHibernateTemplate().delete(o)的时候,就可能会出现org.hibernate.StaleStateException。

我觉得这个异常出现的原因和内存回收有关系,在内存回收的时候。在session关闭的时候,这些数据会变成游离态,如果JAVA虚拟机没有进行垃圾回收的话,在执行delete操作时是没问题的。如果内存不够,或者有频繁的其他操作影响垃圾回收了,那在执行delete操作时就会出现这个问题。

另外,如果直接通过new一个object,生成主键之类的数据,直接delete数据,基本上也会出现这个问题。

解决的方法可以是:在每次的delete之前,先根据主键进行查询操作,如果不为null,再进行delete操作。

另外,直接通过sql进行delete操作应该也可以。update,save等操作应该也是同一个问题。


另外欢迎大家提其他的解决方案。


Hibernate: delete from PA_THIRDLOG where streamNumber=?           
Hibernate: delete from PA_THIRDLOG where streamNumber=?          
ERROR  - Could not synchronize database state with session                
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:61)       
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)    
    at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:24)                 
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2525)     
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2702)    
    at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:77)        
    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:172)       
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)       
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)                 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)                               
    at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390)          
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:420)           
    at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)       
    at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:846)          
    at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:842)  

ERROR  - Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: 

Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1      
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 

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

expected: 1
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:672)    
    at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)       
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)          
    at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)      
    at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:846)           
    at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:842)   
1
0
分享到:
评论
12 楼 风云无浪 2012-10-21  
jinnianshilongnian 写道

不讨论了。
我觉得你对垃圾回收 和 hibernate状态改变理解有偏差。 解决了就好了

垃圾回收的时候,不是清理了内存数据,而是清理hibernate的session中缓存的非持久态内容的索引吧,就导致了这个StaleStateException,session内容不匹配。
现在的话,先getObject再deleteObject在一些极端的情况下,还是会出现问题。现在只有试试用纯sql根据id删除了,等测试组再测试下观察观察再讨论吧。
11 楼 jinnianshilongnian 2012-09-29  
风云无浪 写道
jinnianshilongnian 写道

你都拿到这个对象了 怎么可能垃圾回收  没有引用的对象才会垃圾收集

是垃圾回收的时候清理的hibernate非持久态的数据

不讨论了。
我觉得你对垃圾回收 和 hibernate状态改变理解有偏差。 解决了就好了
10 楼 风云无浪 2012-09-29  
jinnianshilongnian 写道

你都拿到这个对象了 怎么可能垃圾回收  没有引用的对象才会垃圾收集

是垃圾回收的时候清理的hibernate非持久态的数据
9 楼 jinnianshilongnian 2012-09-28  
风云无浪 写道
jinnianshilongnian 写道

跟状态无关 delete方法没有要求model必须是什么状态的

是不要求状态,但是游离态会被垃圾回收了,所以getHibernateTemplate().delete(o)就找不到了。
先getHibernateTemplate().get(class,id)后再进行getHibernateTemplate().delete(o)在40W数据处理的时候没啥问题。但是连接外部socket异常的时候,也还是会出问题。
现在只有试试用sql语句删除了。


你都拿到这个对象了 怎么可能垃圾回收  没有引用的对象才会垃圾收集
8 楼 风云无浪 2012-09-28  
jinnianshilongnian 写道

跟状态无关 delete方法没有要求model必须是什么状态的

是不要求状态,但是游离态会被垃圾回收了,所以getHibernateTemplate().delete(o)就找不到了。
先getHibernateTemplate().get(class,id)后再进行getHibernateTemplate().delete(o)在40W数据处理的时候没啥问题。但是连接外部socket异常的时候,也还是会出问题。
现在只有试试用sql语句删除了。

7 楼 jinnianshilongnian 2012-09-28  
风云无浪 写道
jinnianshilongnian 写道
你可以禁用缓存然后测试看看是不是有问题。
你先查一次 如果缓存中有还是能命中的 所以此处可以肯定不是缓存的问题。
不知道你4w数据怎么分的,不好下结论。

其实我说缓存也不准确。应该是hibernate的数据状态,持久态应该是在session.close后就结束了,就变成了游离态,所以就会被JVM回收。map的频繁delete操作就可能触发了垃圾回收。
再查一次的话,就会从游离态变成持久态,就不会有问题了。
4W数据的话,是每次从表里读出来2000的数据,然后分给各个线程(用的是newFixedThreadPool),所以要加到map里或者set里判重,不重复发给子线程。
关于hibernate的持久态、游离态、托管态在什么时候转换,和spring管理的session啥时候触发这些状态的转换,我也不清楚。


4W数据的话,是每次从表里读出来2000的数据,然后分给各个线程(用的是newFixedThreadPool),所以要加到map里或者set里判重,不重复发给子线程。
这才是根本问题, 不重复发。

跟状态无关 delete方法没有要求model必须是什么状态的
6 楼 风云无浪 2012-09-27  
jinnianshilongnian 写道
你可以禁用缓存然后测试看看是不是有问题。
你先查一次 如果缓存中有还是能命中的 所以此处可以肯定不是缓存的问题。
不知道你4w数据怎么分的,不好下结论。

其实我说缓存也不准确。应该是hibernate的数据状态,持久态应该是在session.close后就结束了,就变成了游离态,所以就会被JVM回收。map的频繁delete操作就可能触发了垃圾回收。
再查一次的话,就会从游离态变成持久态,就不会有问题了。
4W数据的话,是每次从表里读出来2000的数据,然后分给各个线程(用的是newFixedThreadPool),所以要加到map里或者set里判重,不重复发给子线程。
关于hibernate的持久态、游离态、托管态在什么时候转换,和spring管理的session啥时候触发这些状态的转换,我也不清楚。
5 楼 jinnianshilongnian 2012-09-27  
这绝对是缓存的问题,我还没这么弱让sql执行两次啊:  你可以禁用缓存然后测试看看是不是有问题。

我最终的处理方法就是在getHibernateTemplate().delete(o)前,先查询一次,如果不为null,再执行删除,然后也在map里进行删除。 
你先查一次 如果缓存中有还是能命中的 所以此处可以肯定不是缓存的问题。



不知道你4w数据怎么分的,不好下结论。
4 楼 风云无浪 2012-09-27  
jinnianshilongnian 写道

Hibernate: delete from PA_THIRDLOG where streamNumber=?  是执行了两次 还是日志打印重复了? 
此处很明显sql执行了。 怀疑删除执行了两次。

那个两次可能是不同线程打印出来的。
这绝对是缓存的问题,我还没这么弱让sql执行两次啊。。
这么说吧,我这个是处理4万数据时候出的问题。我在主线程里把4万个数据分给100个线程。
线程处理的数据我加到ConcurrentHashMap里了(其他的多线程容器也一样),线程处理完一条数据,就在map里删掉相应的记录。这时用getHibernateTemplate().delete(o)时就会有这个异常。如果不在map里删掉相应的记录,就不会有这个异常。所以我怀疑是垃圾回收造成的非持久态数据的清理。

我最终的处理方法就是在getHibernateTemplate().delete(o)前,先查询一次,如果不为null,再执行删除,然后也在map里进行删除。跑40W数据也没出现问题

3 楼 jinnianshilongnian 2012-09-27  
1、垃圾回收不就是内存回收么?回收的是hibernate的缓存,不是数据,这个是由于hibernate缓存的数据不一致造成。

hibernate缓存的数据是需要过期才能垃圾回收的。

2、我觉得应该是这个Also occurs if we try delete or update a row that does not exist.只不过not exist的是缓存。  如果缓存中没有 会查二级缓存 

此处跟缓存无关


3、Could not synchronize database state with session
Hibernate: delete from PA_THIRDLOG where streamNumber=?                                                                                                                                                                                                                                                                          
Hibernate: delete from PA_THIRDLOG where streamNumber=?                                                                                                                                                                                                                                                                          
ERROR  - Could not synchronize database state with session                                                                                                                                                                                                                                                                       
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1     

Hibernate: delete from PA_THIRDLOG where streamNumber=?  是执行了两次 还是日志打印重复了? 
此处很明显sql执行了。 怀疑删除执行了两次。
2 楼 风云无浪 2012-09-27  
jinnianshilongnian 写道
我觉得这个异常出现的原因和内存回收有关系,在内存回收的时候。 跟垃圾回收无关,况且你拿着这个model的引用不可能回收。

StaleStateException异常描述:
public class StaleStateException
extends HibernateException
Thrown when a version number or timestamp check failed, indicating that the Session contained stale data (when using long transactions with versioning). Also occurs if we try delete or update a row that does not exist.

Note that this exception often indicates that the user failed to specify the correct unsaved-value strategy for a class!

能否贴出详细异常,需要看一下详细异常。


垃圾回收不就是内存回收么?回收的是hibernate的缓存,不是数据,这个是由于hibernate缓存的数据不一致造成。
这个异常的描述我也看了,我觉得应该是这个Also occurs if we try delete or update a row that does not exist.只不过not exist的是缓存。
Hibernate: delete from PA_THIRDLOG where streamNumber=?           
Hibernate: delete from PA_THIRDLOG where streamNumber=?          
ERROR  - Could not synchronize database state with session                
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:61)       
    at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)    
    at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:24)                 
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2525)     
    at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2702)    
    at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:77)        
    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:172)       
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)       
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)                 
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)                               
    at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390)          
    at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:420)           
    at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)       
    at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:846)          
    at org.springframework.orm.hibernate3.HibernateTemplate.delete(HibernateTemplate.java:842) 
1 楼 jinnianshilongnian 2012-09-27  
我觉得这个异常出现的原因和内存回收有关系,在内存回收的时候。 跟垃圾回收无关,况且你拿着这个model的引用不可能回收。

StaleStateException异常描述:
public class StaleStateException
extends HibernateException
Thrown when a version number or timestamp check failed, indicating that the Session contained stale data (when using long transactions with versioning). Also occurs if we try delete or update a row that does not exist.

Note that this exception often indicates that the user failed to specify the correct unsaved-value strategy for a class!

能否贴出详细异常,需要看一下详细异常。

相关推荐

Global site tag (gtag.js) - Google Analytics