org.hibernate.AssertionFailure:例如,无法执行un-delete

时间:2013-05-27 18:38:37

标签: hibernate assertion

当我尝试在一些删除操作后进行读取时,我得到了这个hibernate断言错误。

我找不到任何关于“无法执行取消删除”错误的任何内容,except the soure code,所以我想,也许我正在做一些明显错误的事情......

堆栈跟踪在下面,

AssertionFailure:43 -  - HHH000099: an assertion failure occured (this may indicate a bug in         Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: Unable     to perform un-delete for instance X
org.hibernate.AssertionFailure: Unable to perform un-delete for instance X
   at org.hibernate.engine.spi.ActionQueue.unScheduleDeletion(ActionQueue.java:508)
   at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:157)
   at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
   at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
   at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
   at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
   at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
   at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
   at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
   at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
   at org.hibernate.event.internal.DefaultPersistEventListener.justCascade(DefaultPersistEventListener.java:190)
   at org.hibernate.event.internal.DefaultPersistEventListener.entityIsDeleted(DefaultPersistEventListener.java:229)
   at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:158)
   at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
   at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
   at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
   at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
   at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
   at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
   at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
   at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
   at org.hibernate.event.internal.DefaultPersistEventListener.justCascade(DefaultPersistEventListener.java:190)
   at org.hibernate.event.internal.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:183)
   at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:147)
   at org.hibernate.internal.SessionImpl.firePersistOnFlush(SessionImpl.java:870)
   at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:863)
   at org.hibernate.engine.spi.CascadingAction$8.cascade(CascadingAction.java:346)
   at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
   at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
   at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
   at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
   at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
   at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
   at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
   at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
   at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:160)
   at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:151)
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1186)
   at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1241)
   at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
   at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:257)
   at org.hibernate.ejb.criteria.CriteriaQueryCompiler$3.getResultList(CriteriaQueryCompiler.java:254)

此致

10 个答案:

答案 0 :(得分:2)

我有同样的问题。发生的事情是我正在删除相关的bean,让我们称它们为A和B.我删除了Bs然后继续查找链接到As的实体C,并将类型A的bean作为参数进行查询并使查询导致此异常。我最好的猜测是实体D上的Cascade注释,引用A和B,删除了As,当我删除Bs然后给出一个已在DB级别上删除的实体作为查询的参数导致问题。

重新排列代码,以便我首先删除C中的引用到A和然后继续删除B和A似乎可以解决这个问题。

答案 1 :(得分:1)

我今天也使用Hibernate 4.x作为JPA 2.x提供程序,面对同样的堆栈跟踪。以下是我了解到需要更改以修复此引发的异常的内容。

在我的JPA映射域模型中,我有一个基于OneToMany的深图,A有很多B,B有很多C,C有很多D,D有很多Es。所有对manys的级联类型是ALL。后面的指向ManyToOne存在于每个级别,当我们编写的代码都是默认的(即,急切加载)时,我们编写的代码工作正常

在我今天诊断出来的违规用例中,我们使用JPQL查询读取了一组离散的Ds,当我​​们遍历该集合时,我们调用EntityManager.remove(c),我们通过询问a获取c实例其父/所有者C实例的D实例。

如果通过延迟加载的D到C关系获得该c实例,则对EntityManager.remove(c)的调用不会报告,但后续调用EntityManager.flush()会导致主题异常。

不会引发主题异常,如果在该JPQL查询中,通过添加“join fetch d.c c”来急切地加载从D到C的关系。

所以,只是想我会分享这些结果以防其他人面对这个问题而且上面的内容让他们知道他们可能会改变什么来解决这个问题。

答案 2 :(得分:1)

这适用于所有通过搜索无法删除断言(像我一样)来到这里的人。

在承包商给我们留下的一些代码中,Assertion遇到了同样的问题,但对我来说,问题不在于级联,而是运行良好。

出于某种原因,Hibernate在同一个会话中加载了同一个实体两次。我深入挖掘Hibernate内部时才发现这一点。

我使用了org.hibernate.stat.SessionStatistics,你可以得到Session 你得到的SessionImpl

的PersistenceContext
Session session = (Session)this.entityManager.unwrap(Session.class);
persistenceContext = ((SessionImpl)session).getPersistenceContext();

找出Hibernate加载的内容。

当我用

打印出完整的实体列表时
public  void printSessionInfo(String where,HashSet<String> printClasses){
        Log log = Logging.getLog(PersistentSesionInfo.class);
        Session session = (Session)this.entityManager.unwrap(Session.class);

        SessionStatistics stats = session.getStatistics();
        HashMap<String,Counter> entityMap = new HashMap<String,Counter>();
        if(stats!=null){
            log.info("EntityManager #0 has #1 managed entities and #2 collections at #3", getHash(entityManager),stats.getEntityCount(),stats.getCollectionCount(),where);
            List<EntityKey> entities = com.google.common.collect.Lists.newArrayList(stats.getEntityKeys());
            Iterator<EntityKey> iter = entities.iterator();
            while(iter.hasNext()){
                EntityKey ek = iter.next();
                if(entityMap.containsKey(ek.getEntityName())){
                    entityMap.get(ek.getEntityName()).increase();
                }else{
                    entityMap.put(ek.getEntityName(), new Counter());
                }
                if(printClasses!=null && printClasses.contains(ek.getEntityName())){
                    try{
                    Object o = ((HibernateSessionProxy)session).get(ek.getEntityName(), ek.getIdentifier());
                    if(o!=null){
                        log.info("Entity #0 of type #1  id=#2 System hash=#3 object hash #4", o,Hibernate.getClass(o).getSimpleName(),ek.getIdentifier(),Integer.toHexString(System.identityHashCode(o)),Integer.toHexString(o.hashCode()));
                    }
                    }catch(javax.persistence.EntityNotFoundException e ){
                        log.error("Entity #0 with id #1 cannot be found anymore", ek.getEntityName(),ek.getIdentifier());
                    }
                }
            }
            for(Entry<String,Counter> entry : entityMap.entrySet()){
                log.info("Entity #0 count #1", entry.getKey(),entry.getValue());
            }

        }
    }
public class Counter {
        int count = 1;

        public void increase(){
            count++;
        }

        public int getCount(){
            return count;
        }

        public String toString(){
            return String.valueOf(count);
        }
    }

我的实体列在那里,但是当我使用

persistenceContext.getEntry(myEntity)

它返回null(entityManager.contains(myEntity)返回true)!

我从persistenceContext.getEntitiesByKey()遍历所有EntityKeys(您可能需要在迭代之前复制列表)

List<EntityKey> list = new ArrayList<EntityKey>();
list.addAll(persistenceContext.getEntitiesByKey().keySet());

在那里,EntityKey for myEntity就在那里,但它指向另一个实例(不同的System.identiyHashCode)。

我必须假设问题最终是使用实体的equals和hashCode方法(因为经常出现实体问题)。我注意到类似的实体实例将具有相同的hashCode,即使它们的父级不同。

我已经使用'必须假设'因为问题没有立即消失(因为我使用liverebel没有重启服务器)。只有在Hibernate上启用了TRACE重启服务器后,问题才会消失。在回滚所有其他调试更改并且仅保留equals / hashCode方法之后,它仍然有效。

因此,每当您的实体出现奇怪的无法解释的问题时 - 请检查equals和hashCode方法!并使用Hibernate类PersistenceContext和SessionStatistics来调试它。

答案 3 :(得分:1)

我知道这是非常晚的答案,但这可能会对某人有所帮助,将来某个时候! 这个答案是关于类似的错误(如果有人登陆这个问题,幸运的话):AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)

我收到此错误是因为我试图save session实体的not-null属性 - 主键设置为null

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "calc_id", unique = true, nullable = false)
private Long calcId;

此处GenerationType.IDENTITY无效,未在save之前设置主键值。和Tadaa ......我得到了和我提到的相同的错误。 所以我只是用以下代码替换了代码。

@SequenceGenerator(name="identifier", sequenceName="mytable_id_seq", allocationSize=1)  
@GeneratedValua(strategy=GenerationType.SEQUENCE, generator="identifier")

答案 4 :(得分:0)

它 可能是一个hibernate的bug,如果你读(load()一个代理实例)然后调用delete并保存它。 https://hibernate.atlassian.net/browse/HHH-8374

答案 5 :(得分:0)

我有同样的错误。 我有A班和B班。 B有一个As列表,A有一个返回B的引用。 A还引用了对象C(Cascade.All),它导致取消删除时出现异常。

我试图将A的对象重新定位到B的另一个对象。

这会导致异常:

objectOfA.getObjectOfB().getListOfAs().remove(objectOfA);
objectOfB1.getListOfAs().add(objectOfA);
objectOfA.seObjectOfB(objectOfB1);

dao.flush()

这是可行的解决方案。

objectOfA.seObjectOfB(objectOfB1);

dao.flush()

bjectOfA.getObjectOfB().getListOfAs().remove(objectOfA);
objectOfB1.getListOfAs().add(objectOfA);

最后两行并不总是强制性的,因为hibernate会在重新加载后对此进行更正。

如果它是一个休眠的bug,我不会感到害羞。由于hibernate在ActionQueue.unScheduleDeletion()

中将对象C与相同C的代理与“==”进行比较,因此发生异常。

答案 6 :(得分:0)

我曾经遇到过这个问题。在使用多个@OneToMany并使用 mappedby annotatin时使用双向映射的情况下,服务器会显示此类错误。因此,您可以使用

轻松解决问题
@JoinTable(name="c",joinColumns=@JoinColumn(name="c_id"),inverseJoinColumns=@JoinColumn(name="l_id"))

而不是使用mappedby ..

答案 7 :(得分:0)

我使用 cascade = CascadeType.ALL 并且它工作正常,假设您在实体B上获得它,它是从实体A中提取的。请将级联全部放在A上,

还取决于谁在我的情况下保持关系,关系是由A映射的。

答案 8 :(得分:0)

我的两分钱,对于那些到达这个主题并使用Grails的人。

在mi的情况下,问题来自于将域持久属性更改为瞬态属性(提供特定的setter和getter),以及使用map版本并将变量传递给那里的构造函数。

原始域类是这样的:

class MyDomain {
    String content
}

我正在创建一个像

这样的实例
def domain = new MyDomain( content: "sample content" )

更新域名:

class MyDomain {
    static transients = [ 'content' ]

    byte[] compressed

    String getContent() {
        compressed ? uncompress( compressed ) : null
    }

    void setContent( String content ) {
        compressed = content ? compress( content ) : null 
    }
}

构造函数不会抱怨,但是没有调用setContent,奇怪的是它没有给出验证错误或SQL错误,而是引发了这个线程中提到的错误。

解决方案很简单:

def domain = new MyDomain()
domain.content = "sample content"

这样就可以调用setter。

答案 9 :(得分:-1)

从您的实体中删除方法hashCode和equals。它对我有用