Hibernate 批处理操作未按预期工作

发布于 2024-10-05 22:59:40 字数 504 浏览 2 评论 0原文

我有一个包含以下字段的 Person 类 -

id、hashedId、描述

id 是序列生成的主键,hashedId 不为 Null。

我执行以下操作:

  1. session.saveOrUpdate(person)
  2. person.setHashedId(hash(person.getId()))

Id 在数据库中自动生成。当我这样做时,我不应该只期待 2 个语句吗

  1. 选择获取下一个序列Id(人物id)
  2. 插入要插入人员记录吗?

但是,它正在尝试在步骤 1 之后(当然是在最终事务提交期间)使用 null hashedId 进行插入 - 我收到约束冲突错误 - HashedId 不能为 null。

I have a Person class with the following fields-

id, hashedId, description

id is the primary key generated by a sequence and hashedId is Not Null.

I do the following:

  1. session.saveOrUpdate(person)
  2. person.setHashedId(hash(person.getId()))

The Id is autogenerated in the DB. When I do this, shouldnt I expect only 2 statements

  1. Select to get the next sequence Id (person id)
  2. Insert to insert the person record?

However, It is trying an insert right after step 1(during final transaction commit, ofcourse) with null hashedId - I get back a constraint violation error - HashedId cannot be null.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

む无字情书 2024-10-12 22:59:40

当您调用 Session.save() 或类似方法时,Hibernate 将立即生成 ID 并执行插入操作,而不是简单地将其排队以便稍后保存。因此,在插入元素之前不会有间隙分配其 ID。对于“身份”ID 生成策略,无论如何将它们分开是完全不可能的......

根据我的经验,处理这种情况的最安全和最简单的方法是使用拦截器(或者可能是事件监听器?)来捕获在未设置 hashedId 属性的情况下插入实体,并在保存之前生成它。这有点令人不快,但恕我直言,这比将 ID 生成提取到应用程序代码中要好。

下面是我生成新票证实体的“引用”属性的示例(使用拦截器):

public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
    Type[] types) {
    boolean changed = super.onSave(entity, id, state, propertyNames, types);

    if (entity instanceof Ticket) {
        for (int i = 0; i < propertyNames.length; i++) {
            if (propertyNames[i].equals("reference") && state[i] == null) {
                state[i] = generateTicketReference((Integer) id);
                changed = true;
            }
        }
    }

    return changed;
}

When you call Session.save() or similar, Hibernate will immediately generate IDs and do the insert rather than simply queueing it up to be saved later. So there's no gap in which the element has its ID assigned before it's inserted. For the 'identity' ID generation strategy, it's completely impossible to split these up anyway...

In my experience, the safest and simplest way to handle this kind of case is to use an Interceptor (or maybe an EventListener?) to trap the entity being inserted with the hashedId property unset, and generate it just before the save. It's a bit unpleasant, but IMHO better than pulling ID generation up into the application code.

Here's an example where I generate the 'reference' property of a new Ticket entity (using an Interceptor):

public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
    Type[] types) {
    boolean changed = super.onSave(entity, id, state, propertyNames, types);

    if (entity instanceof Ticket) {
        for (int i = 0; i < propertyNames.length; i++) {
            if (propertyNames[i].equals("reference") && state[i] == null) {
                state[i] = generateTicketReference((Integer) id);
                changed = true;
            }
        }
    }

    return changed;
}
污味仙女 2024-10-12 22:59:40

Hibernate 正在做正确的事情:-) 请参阅 http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-id,“5.1.4.4 标识列和序列”部分。

这是因为 Hibernate 不知道 ID 是由数据库生成的。并且 ID 并不会因为您调用了序列而真正分配给记录。因此,您应该让 Hibernate 保存记录并检索记录的实际 ID,或者您应该使用 Hibernate 生成的 ID(如 hilo)(或自己生成,生成器类型为“已分配”)。

Hibernate is doing the right thing :-) See http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping-declaration-id , section "5.1.4.4. Identity columns and sequences"

That's because Hibernate doesn't knows about the ID if it's generated by the DB. And the ID is not really assigned to a record just because you called a sequence. So, you should either let Hibernate save the record and retrieve the actual ID for the record, or you should use a Hibernate-generated ID (like hilo) (or generate it yourself, with generator type "assigned").

凝望流年 2024-10-12 22:59:40

HashedId 字段是从 ID 派生的,对吧?我想基于一个廉价的功能?那么在这种情况下,您真的需要将该字段保留在数据库中吗?你直接在查询中使用它吗?
难道你不能让 getHashedId() 方法总是返回 hash(this.id) 吗?这样你就不会在数据库中拥有该 hashedId 字段,并且你不必管理它 - 因为它只是根据 id 推导出来的。

希望这有帮助。

The HashedId field is derived from the ID, right? based on an inexpensive function, I assume? So in this case do you really need to persist that field in the DB? Do you use it directly in queries?
Can't you just have the getHashedId() method always return hash(this.id)? This way you won't have that hashedId field in the DB and you won't have to manage it - as it's simply deduced based on the id.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文