SpringとHibernateを使用する私のアプリケーションでは、CSVファイルを解析し、CSVファイルからレコードが読み取られるたびにhandleRow()
を呼び出してdbにデータを入力します。
私のドメインモデル:
「ファミリ」には「サブファミリ」が多数あります
「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);
}
}
種は、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)
任意のヒント?
merge()
を使用します。例外は、現在のセッションが渡すエンティティをすでに認識していることを意味します。そうでない場合は、hashCode()
およびequals()
をどのようにオーバーライドしたかを確認してください。エンティティによって異なる値が返されるはずです。
delete()
またはupdate()
を実行している場合にも、この問題が発生する可能性があります。おそらくDTOからhibernateにマップされたpojoを自分でビルドした場合、問題が発生する可能性があります。このpojoは、すでにSession
にあるものと同じ識別子を持っているため、問題が発生します。
2つのオプションがあります。 @Bozhoが言ったことを行い、最初にオブジェクトをmerge()
します。これで更新は完了です。削除するには、merge()
から返されたオブジェクトを取得して削除します。
もう1つのオプションは、最初にオブジェクトのIDを使用してSession
をクエリし、次にそれを削除または更新することです。
私はそう解決しました:削除メソッドについて:
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();
オブジェクトをsaveOrUpdate()呼び出しの後にセッションから更新する場合は、オブジェクトのhashCode実装も確認してください。
EntityのID列にGeneratedValueアノテーションがない場合にこれが発生しました。
@GeneratedValue(strategy = GenerationType.AUTO)
Session
のインスタンスを2つ作成した可能性があります
Session session = factory.openSession();
1つの関数で1つのセッションを開き、別のセッションを作成して別の関数を実行した場合、この問題が発生します。
これは、複合キーの一部がnullだったために起こりました。例:
@Id
@Column(name = "id")
private String id;
@JoinColumn(name = "id")
private Username username;
IDが異なっていても、たまたまユーザー名がnullであるため、nullの「主キーの重複」が発生しました。