【问题标题】:Hibernate "Provided id of the wrong type expected Long, got class DelayedPostInsertIdentifier" exceptionHibernate“提供了错误类型的预期Long的ID,得到了类DelayedPostInsertIdentifier”异常
【发布时间】:2015-01-12 02:11:15
【问题描述】:

简而言之:

当我尝试将 New(Unsaved) Entities 添加到一对多的已保存父实体集时,在父实体上调用 Merge 后,我收到以下异常:

为类 com.test.Child 提供了错误类型的 id。预期的: 类 java.lang.Long,得到类 org.hibernate.action.internal.DelayedPostInsertIdentifier

我找到了一张代表相同问题的票:https://hibernate.atlassian.net/browse/HHH-2382 它被拒绝了,对我的问题没有多大帮助。

有人遇到过这个问题吗? 谁能指出问题的根源和可能的解决方案?

问题详情:

我有两个课程: 公共类父扩展BaseModel实现可序列化{ 私人长ID; 私人 Set 孩子; }

public class Child extends BaseModel implements Serializable {
    private long id;
    private String value;
}

我正在尝试执行以下代码:

Parent parent = new Parent();
parent.setChildren(new HashSet<Child>());

Child child = new Child();
child.setValue("First");
parent.getChildren().add(child);

parent = daoFacade.save(parent);

child = new Child();
child.setValue("Second");
parent.getChildren().add(child);

parent = daoFacade.save(parent);

第二次调用 save 方法后,我得到以下异常:

org.hibernate.TypeMismatchException:为 com.text.Child 类。预期:类 java.lang.Long,得到类 org.hibernate.action.internal.DelayedPostInsertIdentifier 在 org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:134) 在 org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1092) 在 org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1019) 在 org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:648) 在 org.hibernate.type.EntityType.resolve(EntityType.java:468) 在 org.hibernate.type.EntityType.replace(EntityType.java:325) 在 org.hibernate.type.CollectionType.replaceElements(CollectionType.java:517) 在 org.hibernate.type.CollectionType.replace(CollectionType.java:667) 在 org.hibernate.type.TypeHelper.replace(TypeHelper.java:177) 在 org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:372) 在 org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:184) 在 org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:157) 在 org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76) 在 org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914) 在 org.hibernate.internal.SessionImpl.merge(SessionImpl.java:898) 在 org.hibernate.internal.SessionImpl.merge(SessionImpl.java:902) 在 com.test.DAOFacade.saveObject(DAOFacade.java:273) 在 com.test.Test.testSaving(MemcachedTest.java:99)

DaoFacade.save 方法如下所示:

public void saveOrUpdate(T obj) {
    Session session = getSession();

    BaseModel model = (BaseModel) obj;
    if (model.isNew()) {
        T merged = (T)session.merge(obj);
        session.update(merged);
    } else {
        session.saveOrUpdate(obj);
    }
    session.flush();
}

Hibernate 映射是:

<class name="Parent" table="PARENT">
    <id name="id" column="id" unsaved-value="0">
        <generator class="native"/>
    </id>
    <set name="children" inverse="false" lazy="false" cascade="all">
        <cache usage="read-write" />
        <key column="LINK_ID"/>
        <one-to-many class="Child"/>
    </set>       
</class>

<class name="Child" table="CHILD">
    <cache usage="read-write" />

    <id name="id" column="id" unsaved-value="0">
            <generator class="native"/>
        </id>

        <property name="value" type="string" column="VALUE" not-null="true" lazy="false"/>       
</class>

我已经调试了几个小时,所有进程在 Hibernate 中似乎都正常,但实际上它导致了以下问题:

  • 在合并期间,在迭代字段期间,未保存的“第二个”子项是 找到了。
  • “第二个”子级标记为插入,插入查询已准备好并被放入 QueryQueue。
  • 继续合并过程,Hibernate 有时会尝试加载“第二个”子节点
  • 但它尚未插入,并且引发了 Excpetion。

【问题讨论】:

    标签: java hibernate one-to-many hibernate-onetomany


    【解决方案1】:

    我也遇到过这个问题。请注意,您的 saveOrUpdate 方法没有启动事务。解决方案是启动事务并确保在调用 session.update 或 session.saveOrUpdate 后提交事务。

    像这样更新你的 saveOrUpdate 方法:

    public void saveOrUpdate(T obj) {
       Session session = getSession();
       Transaction tx = null;
       try {
          tx = session.beginTransaction();
          BaseModel model = (BaseModel) obj;
          if (model.isNew()) {
            T merged = (T)session.merge(obj);
            session.update(merged);
          } else {
            session.saveOrUpdate(obj);
          }
          tx.commit();
       } catch (Exception ex) {
          tx.rollback();
       }
    
    }
    

    这个thread 提示了我解决问题的方法,并且您的 saveOrUpdate 方法会验证丢失的事务。

    【讨论】:

    • 我们不在那里使用事务,因为我们使用更高级别的事务:我们确实需要在一个事务中更新和创建多个不同类型的实体。有时我们只是不将事务用于不重要的实体(发生异常)。可能,它是问题的根源。我们需要创建一些机制并仅在需要时创建事务。
    • @DmitriiSemenov,当你说你在更高级别上使用事务时,你的意思是你正在使用某种事务管理框架(例如 Spring - spring-tx)?你能告诉我为什么你会在不创建事务的情况下调用 saveOrUpdate 或 update 方法吗?
    【解决方案2】:

    我在使用 Hibernate 4.2.15 和 Spring 时遇到了同样的问题。正如@arjaynacion 所建议的,向执行保存的方法添加@Transactional 注释解决了这个问题:

    @Transactional
     @NotNull
     protected S save(@NotNull S entity)
     {
        return getDao().save(entity);
     }
    

    【讨论】:

      猜你喜欢
      • 2022-10-05
      • 2018-04-08
      • 1970-01-01
      • 2012-06-04
      • 1970-01-01
      • 2015-04-13
      • 2019-10-16
      • 2017-01-19
      • 1970-01-01
      相关资源
      最近更新 更多