咨询:EntityManager.remove()未抛出预期IllegalArgumentException的原因
为什么EntityManager.remove()处理Detached Entity时没抛出IllegalArgumentException?
这问题我之前排查过好几次,其实背后藏着几个JPA规范和实现细节的坑,给你拆解下:
JPA规范≠具体实现的严格执行
JavaDoc里说的抛出异常是JPA规范的要求,但不少主流JPA实现(比如Hibernate)做了“友好兼容”:当你传入detached实体时,它会自动先调用merge()把实体转为managed状态,再执行删除操作,所以不会触发IllegalArgumentException。比如Hibernate的EntityManagerImpl类里的remove方法就有这个逻辑——先检查实体状态,若发现是detached,就先merge再执行删除。实体标识符的有效性影响行为
如果你的detached实体主键是null,或者对应的数据在数据库里根本不存在,有些JPA实现会直接静默跳过删除操作,而不是抛出异常。这种行为虽然不符合规范,但部分实现为了避免无意义的报错,会这么处理。你判断detached的方式可能没问题,但实现逻辑绕开了规范
你说打印结果为false,应该是调用em.contains(entity)返回false吧?这个判断是对的——contains()只对当前EntityManager上下文内的managed实体返回true,返回false确实说明实体是detached状态。但如第一条所说,很多实现不会严格遵守规范抛异常,而是自动处理detached实体。
如果想严格按照JPA规范的要求触发异常,或者明确控制删除逻辑,可以在DAO的delete方法里手动加判断:
public void delete(T entity) { if (!em.contains(entity)) { // 这里可以手动抛出异常,或者转为managed状态再删除 throw new IllegalArgumentException("Cannot remove detached entity"); // 或者 em.remove(em.merge(entity)); } em.remove(entity); }
内容的提问来源于stack exchange,提问作者Dave Mulligan
相关产品推荐
相关产品推荐

