【问题标题】:How to change the ordering of sql execution in hibernate如何在hibernate中更改sql执行的顺序
【发布时间】:2013-12-22 03:07:57
【问题描述】:

我正在尝试使用有序的孩子来建模双向父子设计。

当从父级删除子级(例如,3 个子级中的第 2 个子级)时,hibernate 生成的 sql 导致违反唯一约束,因为“更新”(兄弟)在“删除”(目标)之前执行。

我使用的 RDBMS (H2) 不支持延迟约束。除了以下选项,我还有哪些选择?

  • 从架构中移除唯一约束
  • 自己明确管理排序,而不是依赖休眠

有什么方法可以让休眠生成 sql 之前 'delete' 'update' ?


论坛中发现的一些旧讨论:

DELETE then INSERT in collection - Order of executed SQL


数据库架构:

CREATE TABLE IF NOT EXISTS  Sequences (
ID                      BIGINT NOT NULL AUTO_INCREMENT,
Name                    LONGVARCHAR,
Type                    LONGVARCHAR,
Sequence                LONGVARCHAR,

ParentId                BIGINT DEFAULT NULL,
Index                   INT,

CONSTRAINT pk_SequenceId    PRIMARY KEY     (ID),
CONSTRAINT uc_Sequences     UNIQUE          (ParentId, Index),
CONSTRAINT fk_Sequences
    FOREIGN KEY (ParentId) 
    REFERENCES Sequences(ID) 
        ON UPDATE CASCADE
        ON DELETE CASCADE
);

类:

public class Sequence {
    protected Long ID;
    protected String name;
    protected String type;
    protected String sequence;
    protected Sequence  parentSequence;
    protected List<Sequence> childSequences = new ArrayList<Sequence>();
}

HBM 映射:

<hibernate-mapping>
<class name="Sequence" table="Sequences">
    <id name="ID" column="ID" type="long">
        <generator class="native"/>
    </id>

    <property name="name" type="string" column="Name"/>
    <property name="type" type="string" column="Type"/>
    <property name="sequence" type="string" column="Sequence"/>

    <many-to-one name="parentSequence" column="parentId" cascade="save-update" insert="false" update="false" class="Sequence" />

    <list name="childSequences" inverse="false" lazy="true" cascade="all-delete-orphan">
        <key column="parentId" not-null="true"/>
        <list-index column="Index" base="0"/>
        <one-to-many class="Sequence"/>
    </list>
</class>

【问题讨论】:

    标签: java sql hibernate unique-constraint self-referencing-table


    【解决方案1】:

    Hibernate 不会直接执行 HQL(或 SQL)语句,而是在 commit()flush() 的那一刻重新排序 SQL 语句,以便以最有效的方式执行它们。但它可能会发生从 Hibernate 的重新排序是错误的,例如导致违反约束,就像你的情况一样。

    解决方案是引入一个中间体flush()flush() 强制重新排序并发送 SQL 语句,但它不提交。

    在您的情况下,您可以修改您的代码,例如(作为草图):

    transaction = session.beginTransaction();
    session.delete(obj);
    session.flush();     /* newly introduced */
    session.update(...);
    transaction.commit();
    

    如果问题应该是由 Hibernate 在您无法控制的情况下执行的级联删除或某些删除,那么您必须控制删除和更新过程并在代码中显式执行操作,而不是依赖于休眠。

    【讨论】:

    • 感谢您的建议。手动执行重新排序将非常困难,因为在对象返回到持久性模块之前(例如,在保存时)可能会发生多个操作(交错添加/删除)(如应用程序业务逻辑操作):(
    • 顺便说一句,刷新也可能是隐式的;当您调用特定的选择查询并且仍有待刷新的未决更改时,Hibernate 可能只是决定自己刷新它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    • 2017-09-19
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多