org.hibernate.TransientObjectException:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例
Posted
技术标签:
【中文标题】org.hibernate.TransientObjectException:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例【英文标题】:org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing 【发布时间】:2012-02-27 07:17:21 【问题描述】:在我的项目中,我有 User
、Role
、UserRole
和 BloodGroup
实体。首先,我从 DB 中获取 List<BloodGroup>
并设置为 User
。然后我将User
和Role
实体给UserRole
。之后我将User
插入数据库,然后我尝试插入UserRole
,但出现错误。当我查看 DB 时,BloodGroup
的 ID 没有插入到 User
表中。
如果我选择列表中的第一个 BloodGroup
,则会收到错误消息。其他选项正常。
我在网上看了一下,我找到了cascade = CascadeType.ALL
,但这会将相同的数据添加到BloodGroup
,这意味着我有更多的Arh+ BloodGroup
。
实体:
@Entity
@Table(name="USERS")
public class User implements Serializable
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long userid;
@OneToMany(mappedBy="user")
private List<Userrole> userroles;
//bi-directional many-to-one association to Bloodgroup
@ManyToOne
@JoinColumn(name="BLOODGRUPID")
private Bloodgroup bloodgroup;
@Entity
public class Bloodgroup implements Serializable
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int bloodgroupid;
private String bloodgroupname;
@OneToMany(mappedBy="bloodgroup")
private List<User> users;
@Entity
public class Userrole implements Serializable
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long userroleid;
private Timestamp createddate;
private Timestamp deleteddate;
private String isactive;
//bi-directional many-to-one association to Role
@ManyToOne
@JoinColumn(name="ROLEID")
private Role role;
//bi-directional many-to-one association to User
@ManyToOne
@JoinColumn(name="USERID")
private User user;
控制器:
user.setBloodgroup(bloodGroupImpl.getBloodGroupById(bGroup));
user.setUserid(userImpl.insertUserProfile(user));
userRoleImpl.insertUserRole(user,role);
道:
public void insertUserRole(User user, Role role)
Session session =getHibernateTemplate().getSessionFactory().getCurrentSession();
Userrole uRole = new Userrole();
uRole.setIsactive("1");
uRole.setRole(role);
uRole.setUser(user);
session.save(uRole);
session.flush();
public void insertUserProfile(User user)
Session session = getHibernateTemplate().getSessionFactory().getCurrentSession();
session.save(user);
日志:
Hibernate:
insert
into
IU.Userrole
(userroleid, createddate, deleteddate, isactive, ROLEID, USERID)
values
(default, ?, ?, ?, ?, ?)
05.Şub.2012 19:23:29 com.sun.faces.application.ActionListenerImpl processAction
SEVERE: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.iu.eblood.model.Bloodgroup
javax.faces.el.EvaluationException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.iu.eblood.model.Bloodgroup
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267)
at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:103)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:310)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
【问题讨论】:
能否提供引发错误的代码?只是为了看看你是如何保存实例的。 不要尝试在互联网上随机找到的东西,而应该尝试理解错误的含义,检测抛出异常的位置并修复错误。向我们展示完整的堆栈跟踪和导致引发此异常的代码。 这能回答你的问题吗? How to fix the Hibernate "object references an unsaved transient instance - save the transient instance before flushing" error 【参考方案1】:您的问题将通过正确定义级联依赖关系或在保存引用的实体之前保存引用的实体来解决。定义级联非常棘手,因为它们的使用方式存在所有细微的变化。
这是定义级联的方法:
@Entity
public class Userrole implements Serializable
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long userroleid;
private Timestamp createddate;
private Timestamp deleteddate;
private String isactive;
//bi-directional many-to-one association to Role
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="ROLEID")
private Role role;
//bi-directional many-to-one association to User
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="USERID")
private User user;
在这种情况下,每次保存、更新、删除等Userrole时,关联的Role和User也会被保存、更新……
同样,如果您的用例要求您在更新用户角色时不修改用户或角色,那么只需在修改用户角色之前保存用户或角色
此外,双向关系具有单向所有权。在这种情况下,用户拥有 Bloodgroup。因此,级联只会从 User -> Bloodgroup 开始。同样,您需要将 User 保存到数据库中(附加或使其成为非瞬态),以便将其与 Bloodgroup 关联。
【讨论】:
【参考方案2】:我遇到了类似的问题,尽管我确保首先保存了引用的实体,但它一直失败并出现相同的异常。 经过数小时的调查发现问题出在被引用实体的“版本”列为 NULL。 在我的特定设置中,我首先将它插入到 HSQLDB(这是一个单元测试)中,如下所示:
INSERT INTO project VALUES (1,1,'2013-08-28 13:05:38','2013-08-28 13:05:38','aProject','aa',NULL,'bb','dd','ee','ff','gg','ii',NULL,'LEGACY','0','CREATED',NULL,NULL,1,'0',NULL,NULL,NULL,NULL,'0','0', NULL);
上面的问题是hibernate使用的version列被设置为null,所以即使对象被正确保存了,Hibernate也认为它是未保存的。当确保版本具有 NON-NULL(在这种情况下为 1) 值时,异常消失并且一切正常。
我把它放在这里以防其他人遇到同样的问题,因为这花了我很长时间才弄清楚,而且解决方案与上面的完全不同。
【讨论】:
Hibernate 总是给出最糟糕的错误信息......我工作生活的祸根...... 感谢您的回答....同样的问题让我大伤脑筋...我尝试了各种事务和级联选项,却发现问题是 NULL 版本字段...找不到记录此问题的其他任何地方。 感谢您的回答 - 我也是这种情况,在 Spring Boot 中使用 CommandLineRunner 创建用户时(也有一些值为 NULL 的值,永远不会猜到该对象被视为未保存在这种情况下) 谢谢,这个答案让我省了很多麻烦! +1【参考方案3】:我解决了这个问题,将@Cascade 添加到@ManyToOne 属性。
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
@ManyToOne
@JoinColumn(name="BLOODGRUPID")
@Cascade(CascadeType.MERGE, CascadeType.SAVE_UPDATE)
private Bloodgroup bloodgroup;
【讨论】:
【参考方案4】:不是传递参考对象而是传递保存的对象,下面是解决我的问题的解释:
//wrong
entityManager.persist(role);
user.setRole(role);
entityManager.persist(user)
//right
Role savedEntity= entityManager.persist(role);
user.setRole(savedEntity);
entityManager.persist(user)
【讨论】:
【参考方案5】:在我的情况下,在我的对象中将引用的对象设置为 NULL,然后合并保存方法解决问题,在我的情况下,引用的对象是目录,不需要保存,因为在某些情况下我不需要连它都没有。
fisEntryEB.setCatStatesEB(null);
(fisEntryEB) getSession().merge(fisEntryEB);
【讨论】:
以上是关于org.hibernate.TransientObjectException:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例的主要内容,如果未能解决你的问题,请参考以下文章