如何在hibernate中更改sql执行的顺序

时间:2013-12-05 09:00:25

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

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

当从父项中删除子项(例如3个子项中的子项#2)时,hibernate生成的sql导致唯一约束违规,因为“update”(兄弟)正在“delete”(目标)之前执行。

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

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

有没有办法让hibernate生成带有'delete'的sql在'update'之前?


在论坛中发现了一些陈旧的讨论:

DELETE then INSERT in collection - Order of executed SQL


DB Schema:

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 Mapping:

<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>

1 个答案:

答案 0 :(得分: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执行某些删除,那么您必须控制删除和更新过程并在代码中明确地执行操作,而不是依赖于自动操作冬眠。