【问题标题】:Hibernate unable to save child objects using cascade allHibernate 无法使用 cascade all 保存子对象
【发布时间】:2017-05-16 08:15:54
【问题描述】:

我有以下两个课程。 “类型”类有一个“内容”类的对象。 我想使用 hibernate.save() 方法保存类“类型”的所有引用对象。我已在“内容”类中将级联类型指定为 ALL。

以下是我面临的错误: 对象引用了一个未保存的瞬态实例 - 在刷新之前保存瞬态实例。

有人可以帮我找出问题所在吗?

public class Type {
    @OneToOne
    @JoinColumn(name = "content_id")
    private Content content;
    }

    public class Content {
        @OneToOne(mappedBy = "content", cascade = CascadeType.ALL)
        private Type type;
    }

    public class Test {
        public void createType() {
            Type type = new Type();
            Content content = someMethodToGetContent();
            type.setContent(content);
            save(type); 
        }

        public void save(Object domainObj) {
            getEntityManager().persist(domainObj);
            getEntityManager().flush();
        }
    }

堆栈跟踪:

引起:org.hibernate.TransientObjectException:对象引用 未保存的瞬态实例 - 之前保存瞬态实例 刷新:.content -> .Content at org.hibernate.engine.CascadingAction$9.noCascade(CascadingAction.java:387) 在 org.hibernate.engine.Cascade.cascade(Cascade.java:172) 在 org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154) 在 org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145) 在 org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88) 在 org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) 在 org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) 在 org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795) ... 27 更多 org.springframework.transaction.TransactionSystemException:不能 提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException:事务标记为 回滚仅在 org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) 在 org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:504) 在 org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) 在 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) 在 org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) 在 com.sun.proxy.$Proxy29.persist(Unknown Source) 引起: javax.persistence.RollbackException:事务标记为 回滚仅在 org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73) 在 org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ... 12 更多

【问题讨论】:

  • 试图保存的代码在哪里?它节省了什么?异常的完整堆栈跟踪是什么?
  • 你的班级有瞬态变量吗?
  • @JBNizet:添加代码
  • @LKTN: 没有
  • @minion 你的存档没有带任何参数,什么是 domainObj?这就是你正在传递的东西。

标签: java mysql hibernate


【解决方案1】:

Hibernate 无法使用 cascade all 保存子对象

这不起作用的原因与您尝试保留实体的方式有关。

  • 让我们看看下面的代码在做什么:

    Type type = new Type();
    Content content = someMethodToGetContent();
    type.setContent(content);
    save(type); 
    

您通过调用save(type) 告诉持久性提供程序您要保存type,并且期望content 也应该保存到数据库中。但在实体Type 中,OneToOne 注释不包含PERSIST 级联选项。所以当Type 的实例被持久化时,你必须告诉持久性提供程序来保持Content 的实例,方法是更改​​OneToOne 注释,如下所示:

@OneToOne(cascade=CascadeType.PERSIST)    // modified
@JoinColumn(name = "content_id")
private Content content;

并且因为您定义实体具有双向关系,所以您应该按如下方式正确连接它们:

Type type = new Type();
Content content = someMethodToGetContent();
content.setType(type);                       // modified
type.setContent(content);
save(type); 

【讨论】:

  • 非常感谢您指出我错过了什么。我将级联选项添加到“类型”类并且对象被持久化。非常感谢!
  • 我还有一个问题。假设上述对象“类型”与许多对象“A”、“B”、“C”具有 1-1 关系。我想确保只要“类型”被持久化,“A”、“B”和“C”也是如此。但不是相反,即当我坚持'A'时,我不希望'Type'被坚持。如果我只在“类型”类而不是“A”、“B”、“C”类中添加 CASCADE 选项,这应该可以实现。我说的对吗?
  • 是的。如果A 没有在其1-1 关系上指定级联类型PERSIST,则持久性提供程序将不会尝试持久化引用的实体。但是您应该注意一些事情:如果对应于A 的表持有与对应于Type 的表的外键,并且如果此列标记为NOT NULL,您将收到数据库约束违规错误,因为父实体不会被持久化。
  • 好的。在我的数据库设计中,A、B 和 C 的外键都保存在表“类型”中。
【解决方案2】:

请如下更改您的 createType()。

public void createType() {
Type type = new Type();
Content content = someMethodToGetContent();
content.setType();
type.setContent(content);
save(type); 
}

【讨论】:

  • Sreenath:非常感谢您的回答。正如@ujulu 指出的那样,我在“Type”类中添加了 cascade 选项,并更改了您提到的 createType 方法并保留了 Type 对象,它工作正常。
猜你喜欢
  • 1970-01-01
  • 2011-04-25
  • 2015-03-01
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多