Hibernate的Delete方法给出了StaleStateException

时间:2011-01-18 11:39:26

标签: java hibernate hibernate-mapping

我试图使用Hibernate的删除方法删除对象,但是获取StaleStateException异常。我的要求是基于唯一键删除对象,所以为此我做了类似的事情。

String queryString="from Destination destination "+
                                                   "where destination.destinationID = :destinationid";
    tx.begin();
                Query query= session.createQuery(queryString).setParameter("destinationid", destinationId, Hibernate.STRING);
               @SuppressWarnings("unchecked")
               List<Destination> list=query.list();
               Destination ds=list.get(0);
                 if(!list.isEmpty())
                  session.evict(ds);
                  session.delete(ds);

                  tx.commit();

因为我知道列表中只有一个元素,如果它不是空的,所以只从列表中取出第一个元素(不确定这是不是一个好方法)

但是当我运行这个方法时,我可以在我的控制台中看到以下sql日志

Hibernate: 
    /* delete collection AirTransport.timeTable */ delete 
        from
            tr.TRANSPORTTIME 
        where
            TRANSPORTID=?
Hibernate: 
    /* delete collection AirTransport.timeTable */ delete 
        from
            tr.TRANSPORTTIME 
        where
            TRANSPORTID=?
Hibernate: 
    /* delete collection AirTransport.timeTable */ delete 
        from
            tr.TRANSPORTTIME 
        where
            TRANSPORTID=?
Hibernate: 
    /* delete collection RoadTransport.timeTable */ delete 
        from
            tr.TRANSPORTTIME 
        where
            TRANSPORTID=?
Hibernate: 
    /* delete collection TrainTransport.timeTable */ delete 
        from
            tr.TRANSPORTTIME 
        where
            TRANSPORTID=?
Hibernate: 
    /* delete AirTransport */ delete 
        from
            tr.TRANSPORT 
        where
            UUID=?
Hibernate: 
    /* delete AirTransport */ delete 
        from
            tr.TRANSPORT 
        where
            UUID=?
Hibernate: 
    /* delete AirTransport */ delete 
        from
            tr.TRANSPORT 
        where
            UUID=?
Hibernate: 
    /* delete RoadTransport */ delete 
        from
            tr.TRANSPORT 
        where
            UUID=?

而不是投掷

org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
 at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
 at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
让我怀疑的一件事是,在我的Transport表中,我有三个条目,一个用于AirTransport一个用于Train,最后一个用于Road,在TransPortTime表中我有三个条目用于每个传输类型和

我在所有三个传输类中使用TransportTime作为复合元素

<set name="timeTable" table="TRANSPORTTIME" lazy="true">
                        <key column="TRANSPORTID"/>
                        <composite-element
                                class="TransportTime">

                                <property name="deperatureTime" type="java.util.Date">
                                        <column name="DEPERATURETIME" />
                                </property>
                                <property name="arrivalTime" type="java.util.Date">
                                        <column name="ARRIVALTIME" />
                                </property>
                                <other properties>
                        </composite-element>

                </set>

我仍然无法弄清楚什么是错误的,所以虽然在社区提问


只是添加一些额外信息: 我在目标类中为三个相应的trabsport类提供了以下映射

<set name="airTransport" table="AIRTRANSPORT" inverse="true" lazy="true" cascade="save-update, delete">
        <key>
            <column name="DESTINATIONID" />
        </key>
        <one-to-many class="AirTransport" />
    </set>
    <set name="roadTransport" table="ROADTRANSPORT" inverse="true" lazy="true" cascade="save-update, delete">
        <key>
            <column name="DESTINATIONID" />
        </key>
        <one-to-many class="RoadTransport" />
    </set>
    <set name="trainTransport" table="TRAINTRANSPORT" inverse="true" lazy="true" cascade="save-update, delete">
        <key>
            <column name="DESTINATIONID" />
        </key>
        <one-to-many class="TrainTransport" />
    </set>

并且在我的RoadTransport / Train / Air Transport中有以下映射

<class name="AirTransport" table="TRANSPORT">
        <id name="uuid" type="java.lang.String">
            <column name="UUID" />
            <generator class="uuid"/>
        </id>
        <many-to-one name="destination" class="Destination" fetch="join">
            <column name="DESTINATIONID" />
        </many-to-one>
       <property mappings>
        <set name="timeTable" table="TRANSPORTTIME" lazy="true">
            <key column="TRANSPORTID"/>
            <composite-element
                class="TransportTime">
                <property mappings>
                </composite-element>

        </set>
    </class>

其他两个映射文件也是相同的 所以当我从父类中删除这三个类的映射关联时,我的删除功能开始完美运行。

所以这意味着我在将TimeTable类映射为Transport类(Air / Train / Road Transport类)中的组件时基本上是错误的

这方面的任何建议都会有所帮助

2 个答案:

答案 0 :(得分:3)

当版本号或时间戳检查失败时抛出StaleStateException,表明Session包含过时数据(当使用带有版本控制的长事务时)。如果我们尝试删除或更新不存在的行,也会发生这种情况。

请注意,此异常通常表示用户未能为类指定正确的未保存值策略!

http://www.dil.univ-mrs.fr/~massat/docs/hibernate-3.1/api/org/hibernate/StaleStateException.html

我的猜测是,您的行在此长事务期间会更新。当它尝试提交删除时,它会看到版本不同(会话中标记为删除的版本和db中的实际行),因此抛出StaleStateException

此外,Query类应该有一个名为uniqueResult()的方法,如果你确定每次执行它都会返回一个结果,它将返回一个对象结果。这样可以在尝试获取List部分的第0个索引时节省一些代码。

答案 1 :(得分:1)

您的代码(至少)有两种错误:

  • 在获得第0个项目之前,您必须先检查isEmpty()。否则,您将面临异常风险
  • 你不应该在删除前逐出。摆脱evict()

还要确保没有数据库触发器篡改返回的行数。