静默忽略了删除()


有实体 A 引用(

多对一)实体 B,从 B 到 A 的反向(映射)引用。还有参考 A 到 C 和反向参考 C 到 A。当我发出实体管理器.remove(A) 然后刷新(),"删除"没有被淘汰!但也有例外。就像根本没有调用 remove() 一样。为什么会这样呢?如果在 remove() 之前我们从反向引用 B.listOfA 和 C.listOfA 中提取 A,则按预期生成"delete"。

另请注意我的另一个问题,我得出的结论是,orphanRemoval并不总是按预期工作。现在我开始怀疑也许级联效果很好,但是在那之后,实际的级联移除就像我在这里描述的那样被"吞噬"。

看看这个答案。基本上,JPA 规范要求如果对已删除的实体应用持久操作,则再次对其进行管理。

若要验证是否确实发生这种情况,请为包启用跟踪日志级别org.hibernate并搜索日志条目,如下所示:

un-scheduling entity deletion ...

为避免任何不可预测的行为,建议从加载同一会话/事务的所有其他实体实例中删除对已删除实体的引用。

我遇到了这个问题。即使启用了show_sql:

<property name="hibernate.show_sql" value="true"></property>

没有输出,删除命令被静默忽略。

问题在于一对一关系,其中:待办事项 1 --- * 待办事项

环境是:- JSF- 野蝇 18(JPA 默认实现 - 休眠)- PostgreSQL 10

尝试删除任何一端的实例都会以静默方式失败,服务器的输出上没有相应的"delete"命令,也没有任何类型的异常消息。

溶液

首先,我将 Wildfly18/JBoss 文档中建议的多方代码从:

//    @Override
//    public void delete(Todoitem todoitem) {
//        if (todoitem == null) {
//            return;
//        }
//        if (!emPg.contains(todoitem)) {
//            todoitem = emPg.merge(todoitem);
//        }
//        emPg.remove(todoitem);
//        emPg.flush();
//        emPg.clear();
//    }

到等效形式:

@Override
public void delete(Todoitem todoitem) {
    if (todoitem == null) {
        return;
    }
    Todoitem ti = emPg.find(Todoitem.class, todoitem.getId());
    if(ti == null) {
        return;
    }
    emPg.remove(ti);
    emPg.flush();
    emPg.clear();
}

不幸的是,我得到了相同的结果 - 删除默默地忽略了。

然后,我怀疑数据库,因为休眠处理自己的密钥。我在实施过程中做了很多测试...为了确定一致性问题,我决定清空数据库,删除关系双方的内容。然后,我使用应用程序的资源(无SQL命令)创建新的实体实例和关系,因为除了实体删除之外,一切正常。之后,我使用 SQL 命令检查数据库关系以确保一切正常,确实如此。

接下来,我再次尝试了一个新的测试,但这次成功了。

然后我还原了代码,取消注释了注释的代码,反之亦然,并再次测试。测试再次失败,返回相同的结果 - 静默忽略删除。

我再次将代码设置回以前的条件测试以确认结果。确认成功,确认了对两个问题的怀疑,即数据库和代码实现。

由于好消息,我在"一"端重复了相同的内容(下面的代码 - 注释的代码是从 Wildfly 18 文档中继承的初始代码,如上所述)。

从:

//    @Override
//    public void delete(Todo todo) {
//        if(todo == null) {
//            return;
//        }
//        if (!emPg.contains(todo)) {
//            todo = emPg.merge(todo);
//        }
//        //todoitemDao.deleteAll(todo);
//        emPg.remove(todo);
//        emPg.flush();
//    }

自:

@Override
public void delete(Todo todo) {
    if (todo == null) {
        return;
    }
    Todo t = emPg.find(Todo.class, todo.getId());
    if(t == null) {
        return;
    }
    emPg.remove(t);
    emPg.flush();
    emPg.clear();
}

再次重复测试,但这次不是删除Todoitem实例("多"端),而是删除Todo实例("一"端)。

问题已解决。成功。

重要提示:

直接在数据库上使用 SQL 语句检查删除测试。有时,由于缓存问题或代码实现错误,实例似乎未被删除,需要分开处理。

最新更新