【问题标题】:Spring + Hibernate : a different object with the same identifier value was already associated with the sessionSpring + Hibernate:具有相同标识符值的不同对象已与会话关联
【发布时间】:2011-01-09 19:46:03
【问题描述】:

在我使用 Spring 和 Hibernate 的应用程序中,每次从 CSV 文件中读取记录时,我都会通过调用 handleRow() 来解析 CSV 文件并填充数据库。

我的领域模型:

“家庭”有许多“子家庭”

'SubFamily' 有很多'Locus'

“基因座”属于“物种”

Family <-> SubFamily <-> Locus 都是双向映射。

代码:

public void handleRow(Family dummyFamily, SubFamily dummySubFamily, Locus dummyLocus) {
  //Service method which access DAO layers
  CommonService serv = ctx.getCommonService();

  boolean newFamily=false;
  Family family=serv.getFamilyByFamilyId(dummyFamily.getFamilyId());
  if(family==null){
    newFamily=true;
    family=new Family();
    family.setFamilyId(dummyFamily.getFamilyId());
    family.setFamilyIPRId(dummyFamily.getFamilyIPRId());
    family.setFamilyName(dummyFamily.getFamilyName());
    family.setFamilyPattern(dummyFamily.getFamilyPattern());
    family.setRifID(dummyFamily.getRifID());
  }

  SubFamily subFamily = family.getSubFamilyBySubFamilyId( dummySubFamily.getSubFamilyId() );
  if(subFamily==null){   
    subFamily=new SubFamily();
    subFamily.setRifID(dummySubFamily.getRifID());   
    subFamily.setSubFamilyId(dummySubFamily.getSubFamilyId());
    subFamily.setSubFamilyIPRId(dummySubFamily.getSubFamilyIPRId());
    subFamily.setSubFamilyName(dummySubFamily.getSubFamilyName());
    subFamily.setSubFamilyPattern(dummySubFamily.getSubFamilyPattern());

    family.addSubFamily(subFamily);
  }

  //use the save reference, to update from GFF handler
  Locus locus = dummyLocus;

  subFamily.addLocus(locus);

  assignSpecies(serv,locus);
  //Persist object
  if(newFamily){
    serv.createFamily(family);
  } else {
    serv.updateFamily(family);
  }
}

使用以下方法将 Species 分配给 Locus,该方法仅访问 DAO 层:

private void assignSpecies (CommonService serv, Locus locus) {
  String locusId = locus.getLocusId();
  String speciesId = CommonUtils.getLocusSpecies(locusId, ctx.getSpeciesList()).getSpeciesId();
  //Simply get Species object from DAO
  Species sp = serv.getSpeciesBySpeciesId(speciesId);
  locus.setSpecies(sp);  
}

Hibernate 出现以下错误:

[INFO] Starting scheduled refresh cache with period [5000ms]
Hibernate: insert into species (species_id, name) values (?, ?)
Hibernate: insert into species (species_id, name) values (?, ?)
Hibernate: insert into species (species_id, name) values (?, ?)
############################ROW#####################1
SubFamiyID#######RIF0005913
Hibernate: select this_.id as id1_0_, this_.family_id as family2_1_0_, this_.rif_iD as rif3_1_0_, this_.family_name as family4_1_0_, this_.family_ipr_id as family5_1_0_, this_.family_pattern as family6_1_0_ from family this_ where this_.family_id=?
Creating NEW SubFamiyID#######RIF0005913
Hibernate: select this_.id as id3_0_, this_.species_id as species2_3_0_, this_.name as name3_0_ from species this_ where this_.species_id=?
Hibernate: insert into family (family_id, rif_iD, family_name, family_ipr_id, family_pattern) values (?, ?, ?, ?, ?)
Hibernate: insert into subfamily (sub_family_id, rif_iD, sub_family_name, sub_family_ipr_id, sub_family_pattern, family_id, sub_family_index) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into locus (locus_id, refTrans_id, function, species_id, sub_family_id, sub_family_index) values (?, ?, ?, ?, ?, ?)
Hibernate: update species set species_id=?, name=? where id=?
Hibernate: update subfamily set family_id=?, sub_family_index=? where id=?
Hibernate: update locus set sub_family_id=?, sub_family_index=? where id=?
############################ROW#####################2
SubFamiyID#######RIF0005913
Hibernate: select this_.id as id1_0_, this_.family_id as family2_1_0_, this_.rif_iD as rif3_1_0_, this_.family_name as family4_1_0_, this_.family_ipr_id as family5_1_0_, this_.family_pattern as family6_1_0_ from family this_ where this_.family_id=?
Hibernate: select subfamilie0_.family_id as family7_1_, subfamilie0_.id as id1_, subfamilie0_.sub_family_index as sub8_1_, subfamilie0_.id as id0_0_, subfamilie0_.sub_family_id as sub2_0_0_, subfamilie0_.rif_iD as rif3_0_0_, subfamilie0_.sub_family_name as sub4_0_0_, subfamilie0_.sub_family_ipr_id as sub5_0_0_, subfamilie0_.sub_family_pattern as sub6_0_0_, subfamilie0_.family_id as family7_0_0_ from subfamily subfamilie0_ where subfamilie0_.family_id=?
Hibernate: select locuslist0_.sub_family_id as sub5_1_, locuslist0_.id as id1_, locuslist0_.sub_family_index as sub7_1_, locuslist0_.id as id2_0_, locuslist0_.locus_id as locus2_2_0_, locuslist0_.refTrans_id as refTrans3_2_0_, locuslist0_.function as function2_0_, locuslist0_.sub_family_id as sub5_2_0_, locuslist0_.species_id as species6_2_0_ from locus locuslist0_ where locuslist0_.sub_family_id=?
Hibernate: select species0_.id as id3_0_, species0_.species_id as species2_3_0_, species0_.name as name3_0_ from species species0_ where species0_.id=?
Hibernate: select this_.id as id1_0_, this_.family_id as family2_1_0_, this_.rif_iD as rif3_1_0_, this_.family_name as family4_1_0_, this_.family_ipr_id as family5_1_0_, this_.family_pattern as family6_1_0_ from family this_ where this_.family_id=?
Hibernate: select this_.id as id3_0_, this_.species_id as species2_3_0_, this_.name as name3_0_ from species this_ where this_.species_id=?
Exception in thread "main" [INFO] Closing Compass [compass]
org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [com.bigg.nihonbare.common.domain.Species#1]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.bigg.nihonbare.common.domain.Species#1]
Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.bigg.nihonbare.common.domain.Species#1]
 at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:590)
 at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:284)
 at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223)
 at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:89)
 at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
 at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
 at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
 at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:218)
 at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)

有什么建议吗?

【问题讨论】:

    标签: java hibernate spring dao


    【解决方案1】:

    使用merge()。异常意味着当前会话已经知道您正在传递的实体。如果没有,请检查您如何覆盖 hashCode()equals() - 它应该为不同的实体返回不同的值。

    【讨论】:

    • 有没有办法使用session.saveOrUpdate 更新子实体持久性。我使用了get(),我需要用给定的 ID 更新子实体。合并正在工作,但仅供参考
    • 阅读这篇文章会很有帮助:stevideter.com/2008/12/07/…
    【解决方案2】:

    如果您正在执行delete()update(),也可能会遇到此问题。如果您自己构建休眠映射的 pojo,可能会出现此问题,可能来自 DTO。此 pojo 现在与 Session 中已有的标识符具有相同的标识符,这会导致问题。

    您现在有两个选择。要么按照@Bozho 所说的去做,要么先做merge() 对象。这需要更新。删除时,取merge()返回的对象并删除。

    另一种选择是首先使用对象的 id 查询Session,然后删除或更新它。

    【讨论】:

    • 谢谢!我在删除实体时遇到问题。
    【解决方案3】:

    当实体的 ID 列没有 GeneratedValue 注释时,我已经看到了这种情况:

    @GeneratedValue(strategy = GenerationType.AUTO)
    

    【讨论】:

      【解决方案4】:

      我这样解决: 关于删除方法:

          this.getHibernateTemplate().clear();
      
          this.getHibernateTemplate().delete(obj);
      
          // Esta línea realiza el "commit" del comando
          this.getHibernateTemplate().flush();
      

      关于更新方法:

          this.getHibernateTemplate().merge(obj);
      
          // Esta línea realiza el "commit" del comando
          this.getHibernateTemplate().flush();
      

      【讨论】:

      • 非常适合我。谢谢!
      【解决方案5】:

      如果您在调用 saveOrUpdate() 后从会话中更新对象 evict(),还要检查对象的 hashCode 实现。

      【讨论】:

        【解决方案6】:

        您可能创建了两个Session 实例

        Session session = factory.openSession();
        

        如果您在一个函数中打开了一个会话并在创建另一个会话的同时执行另一个函数,则会出现此问题。

        【讨论】:

          【解决方案7】:

          这发生在我身上,因为我的部分复合键为空。例如:

              @Id
              @Column(name = "id")
              private String id;
          
              @JoinColumn(name = "id")
              private Username username;
          

          用户名碰巧为空,导致“重复”空主键,即使 id 不同。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-11-17
            • 1970-01-01
            • 2011-03-16
            • 2018-03-26
            • 1970-01-01
            • 2020-10-12
            相关资源
            最近更新 更多