如果没有休眠生成的@Id值,则休眠@SelectBeforeUpdate(false)不起作用

时间:2019-03-25 10:40:33

标签: java hibernate

我发现,如果没有休眠的实体映射生成了主键值,则SelectBeforeUpdate(false)将无法正常工作。

@Entity
@SelectBeforeUpdate(false)
class X {
    protected X(){}
    @Id
    @GeneratedValue
    UUID id;

    int x;
}

如果注释掉@GeneratedValue,在X ctor中分配id值,则@SelectBeforeUpdate(false)将失去其功能。

由于处于休眠状态,将通过ForeignKeys.isTransient中的org\hibernate\engine\internal\ForeignKeys.java检查分离的对象是否是瞬态的,该对象最终在IdentifierValue.isUnsaved中调用org\hibernate\engine\spi\IdentifierValue.java。如果没有@GeneratedValue,休眠将使用类UNDEFINED的静态IdentifierValue实例,其中isUnsaved方法始终返回null。这将导致ForeignKeys.isTransient返回null,以便休眠将最终构建快照,这将触发选择SQL。

但是,问题是@GeneratedValue将对象构造分为2个阶段:首先将其新建,然后将其传递到session.save。我不喜欢这样,是否有一种解决方法可以使@SelectBeforeUpdate(false)在不让休眠生成@Id值的情况下工作?我使用UUID作为pk,因此不必让休眠执行此操作。

我使用休眠5

1 个答案:

答案 0 :(得分:0)

最后,我弄清楚了这种机制。对于休眠,无论类型是什么,@Id字段都将在统一过程中进行处理:如果要让休眠为您生成id值,则必须调用session.save,即使id值也可以在对象构造阶段确定。

这是有问题的:如果用户使用UUID作为主键,则意味着用户希望在与数据库通信之前确定该值。对于某些复杂的逻辑,在创建对象A之后,对象A需要做一些其他事情,之后,对象A需要与事务中的另一个对象B一起提交数据库。如果在数据库提交之前对象A的ID为null,则由于对象还不完整,因此非常不便。

Hibernate使用统一ID生成过程作为假设,用于确定对象是否为瞬态。如果添加@GeneratedValue,则仅当id值为null时,休眠对象才是瞬态的(这很简单,如果id值不为null,则必须调用session.save)。如果没有生成器,hibernate无法知道事实,唯一的发现方法就是从数据库中选择它。因此必须忽略@SelectBeforeUpdate(false)

更改过程的唯一方法是自定义一个Interceptor,该Interceptor覆盖Interceptor.isTransient,但是,这需要用户实施瞬态检查。如果始终返回false,则必须精确地调用保存和更新。