3

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

除了源代码之外,我找不到有关此“无法执行取消删除”错误的任何信息,所以我认为,也许我做的事情显然是错误的...

堆栈跟踪如下,

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)

问候,

4

9 回答 9

2

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

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

于 2013-06-12T09:52:51.550 回答
1

这适用于所有通过搜索无法取消删除断言来到这里的人(比如我)。

在承包商留给我们的一些代码中,我对断言有同样的问题,但对我来说,问题不在于级联,它工作得很好。

由于某种原因,Hibernate 在同一个会话中两次加载同一个实体。我只是在深入研究 Hibernate 内部时才发现这一点。

我使用了 org.hibernate.stat.SessionStatistics,你可以从 Session 和 PersistenceContext 中获得,你可以从 SessionImpl 获得

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());

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

我必须假设问题最终出在实体的 equals 和 hashCode 方法上(通常是实体问题)。我注意到,即使它们的父级不同,相似的实体实例也会具有相同的 hashCode。

我使用了“必须假设”,因为问题并没有立即消失(没有重新启动服务器,因为我使用的是 liverebel)。只有在 Hibernate 启用 TRACE 的情况下重新启动服务器后,问题才消失。在回滚所有其他调试更改并仅保留 equals/hashCode 方法后,它仍在工作。

因此,每当您的实体遇到无法解释的奇怪问题时,请检查 equals 和 hashCode 方法!并使用 Hibernate 类 PersistenceContext 和 SessionStatistics 对其进行调试。

于 2013-12-05T14:26:33.300 回答
1

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

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

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

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

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

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

于 2013-11-20T03:40:28.927 回答
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的实体。sessionnot-nullnull

@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")
于 2017-04-07T10:27:42.703 回答
0

这可能是休眠的错误,如果您阅读(加载()代理实例)然后调用删除并保存它。https://hibernate.atlassian.net/browse/HHH-8374

于 2014-01-23T22:22:50.940 回答
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 在重新加载后会更正这一点。

我不确定它是否是休眠中的错误。发生异常是因为 hibernate 将对象 C 与同一 C 的代理与 ActionQueue.unScheduleDeletion() 中的“==”进行比较

于 2014-03-07T13:22:37.283 回答
0

我使用 了cascade = CascadeType.ALL并且它有效,假设您在实体 B 上获取它,该实体 B 是从实体 A 引用的。请将级联全部放在 A 上,

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

于 2017-06-21T08:42:32.730 回答
0

My two cents, for those arriving at this thread and using Grails.

In mi case, the problem came from changing a domain persistent property into a transient one (providing specific setter and getter), and having a constructor using the map version and passing the variable there.

The original domain class was like this:

class MyDomain {
    String content
}

And I was creating an instance like:

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

Updated domain:

class MyDomain {
    static transients = [ 'content' ]

    byte[] compressed

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

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

The constructor would not complain, but setContent is not called, and strangely instead of giving a validation error or an SQL error, it raises the error mentioned in this thread.

The solution is simple:

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

That way the setter gets called.

于 2018-02-15T11:57:40.117 回答
0

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

@JoinTable(name="c",joinColumns=@JoinColumn(name="c_id"),inverseJoinColumns=@JoinColumn(name="l_id"))

而不是使用mappedby ..

于 2017-04-12T09:53:09.280 回答