因此,我有A级和B级。他们使用以下配置共享主键:在A类中,我将B类称为孩子@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)@PrimaryKeyJoinColumnpublic B getB(){ return b;}在类B中,为了从父类A获取ID,我使用以下注释:@Id@GeneratedValue(generator = "customForeignGenerator")@org.hibernate.annotations.GenericGenerator(name = "customForeignGenerator", strategy = "foreign", parameters = @org.hibernate.annotations.Parameter(name = "property", value = "a"))@Column(name = "a_id")public Long getId(){ return id;}@MapsId("id")@OneToOne(mappedBy = "b")@PrimaryKeyJoinColumnpublic A getA(){ return a;}问题是uppon用session.saveOrUpdate(aInstance);DB返回以下错误:Duplicate entry '123456' for key 'PRIMARY'这告诉我们两件事,首先是@MapsId正常工作,将A的ID正确分配给B,其次是冬眠确定它是“保存”而不是“更新”,并且仅在当id为null时对吗? (奇怪吗?)通常的解决方案是从DB和saveOrUpdate中使用旧的B,如果存在的话,但这会带来很多问题,例如也将旧的A从DB转移到会话或使可怕的“ get”休眠关联对象的错误。同样不是很友好的性能,可以轻松完成数据库命中。我的注释中有错误吗?我做错了吗?正常的配置是什么?编辑:这有点违背使用merge手动设置ID的目的,但是由于找不到解决方案,因此我确实手动设置了ID,如下所示:if(aInstance.getId() != null) aInstance.getB().setId(aInstance.getId());session.saveOrUpdate(aInstance);直到片刻之前,这才返回以下错误:org.hibernate.StaleStateException:Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1但是由于某种原因,它停止抛出该错误,现在可以正常工作了。在所有情况下,由于a different object with the same identifier value was already associated with the session可能没有ID,因此先前的代码仍然全部有效,在这种情况下,MapId可以完美地在BD中插入新的A和B。问题仅在更新上。是\是休眠错误吗?大概。我会告诉你们@MapsId何时再次出现。目前,这是一个临时解决方案,直到有人提出了实际的解决方案。 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 我终于找到了所有问题的答案。要了解问题的根源,我们必须提醒saveOrUpdate(object)如何工作。1)如果object设置了ID,则saveOrUpdate将Update否则将Save。2)如果hibernate决定它是一个Save,但是对象已经在DB上,并且要更新,则会出现Duplicate entry '123456' for key 'PRIMARY'异常。3)如果休眠确定它是一个Update,但是对象不在数据库中,则要保存,则发生StaleStateException异常。问题取决于以下事实:如果aInstance存在于数据库中并且已经具有ID,则@MapsId会将ID赋予B,而忽略了上述规则,从而使Hibernate认为B在DB中也可能存在,而不必。仅当A和B在数据库中都不存在或两者都存在时,它才能正常工作。因此,解决方法是确保仅当每个对象都存在于DB中时,才Set ID;如果不存在,则将ID设置为null:B dbB = (B) unmarshaller.getDetachedSession().createCriteria(B.class).add(Restrictions.idEq(aInstance.getId())).uniqueResult();if (dbB != null) //exists in DB{ aInstance.getB().setId(aInstance.getId()); //Tell hibernate it is an Update //Do the same for any other child classes to B with the same strategy if there are any in here}else{ aInstance.getB().setId(null); //Tell hibernate it is a Save}unmarshaller.getDetachedSession().clear();(使用分离的会话,以便主会话保持不需要的对象的状态,避免了“ object with the same identifier in session”异常)如果您不需要数据库对象,而只想知道数据库中是否存在该对象,则可以使用Count,使它更轻巧:String query = "select count(*) from " + B.class.getName() + " where id = " + aInstance.getId();Long count = DataAccessUtils.uniqueResult(hibernateTemplate.find(query));if (count != null && count > 0){ aInstance.getB().setId(aInstance.getId()); // update}else{ aInstance.getB().setId(null); // save}现在您可以saveOrUpdate(aInstance);但是就像我说的那样,@MapsId策略不是非常适合Hibernate。 (adsbygoogle = window.adsbygoogle || []).push({});
10-06 01:06