删除未保存的对象不会调用异常

zzh*_*ads 0 java spring dao hibernate

我正在为我的Dao Spring应用程序编写测试.我发现当我删除未保存的项目时,没有像我期望的那样调用异常,我不知道为什么.

模型:

@Entity
public class Ingredient {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String condition;
    private int quantity;

    public Ingredient() {

    }
}
Run Code Online (Sandbox Code Playgroud)

Dao实施:

@Override
public void delete(Object o) throws DaoException {
    try {
        Session session = mSessionFactory.openSession();
        session.beginTransaction();
        session.delete(o);
        session.getTransaction().commit();
        session.close();
    } catch (Exception ex) {
        throw new DaoException(ex, String.format("Problem deleting %s object (delete method).", o));
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试,期待DaoException:

@Test
public void testDeleteNotSavedThrowsDaoException() throws Exception {
    Ingredient ingredient = new Ingredient("Not saved ingredient","", 1);
    ingredientDao.delete(ingredient);
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*lik 5

Hibernate的Javadoc for Session#delete(Object)状态:

从数据存储中删除持久性实例.该参数可以是与接收会话相关联的实例,或者是具有与现有持久状态相关联的标识符的瞬态实例.

因此传递瞬态实体并不是错误(就像你一样).此外,该Session#delete方法不会声明任何异常,因此未定义当您传入具有DB中不存在的ID的实体时会发生什么.正如你所看到的 - 没有任何反应 - 你要求实体不存在于DB中,它不是从那里开始的,所以没有理由抛出异常(至少根据Hibernate).

将此与基本SQL进行比较DELETE FROM X WHERE ID = Y- 这不会检查记录是否ID=Y存在,它将以任何方式成功(更新0或1行).

在实现传入瞬态实体后具有nullID的UPDATE.

我已经深入研究了Hibernate 5.2.2的来源,Session似乎如果传入的实体没有ID,DELETE则甚至不会对该实体的表执行任何查询.

DefaultDeleteEventListener#onDelete(DeleteEvent, Set):

if (ForeignKeys.isTransient( persister.getEntityName(), entity, null, source ) ) {
    // yes, your entity is transient according to ForeignKeys.isTransient
    deleteTransientEntity( source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities );
    return;
}
Run Code Online (Sandbox Code Playgroud)

现在

protected void deleteTransientEntity(
        EventSource session,
        Object entity,
        boolean cascadeDeleteEnabled,
        EntityPersister persister,
        Set transientEntities) {
    LOG.handlingTransientEntity(); // Only log it
    if ( transientEntities.contains( entity ) ) {
        LOG.trace( "Already handled transient entity; skipping" );
        return;
    }
    transientEntities.add( entity );
    // Cascade deletion to related entities
    cascadeBeforeDelete( session, persister, entity, null, transientEntities );
    cascadeAfterDelete( session, persister, entity, transientEntities );
}
Run Code Online (Sandbox Code Playgroud)

这只会"HHH000114: Handling transient entity in delete processing"在日志中打印而不对实体执行任何操作(但是,如果有任何实际情况,它会将删除级联到相关实体 - 不是您的情况).

所以再一次 - 传递一个没有ID的瞬态实体是可以的 - 它根本不会DELETE在数据库上运行.