org.hibernate.HibernateException: Found shared references to a collection
이 오류는 특정 영속 객체에서 참조하고 있는 객체를 다른 영속 객체에 주입시킬 경우에 사용된다.
하이버네이트에서는 영속 객체에서 컬렉션 프로퍼티 같은 것들을 프락시 패턴을 이용하여 다르게 구현하고 있으므로, 이러한 프락시 객체에 대한 참조를 가져다가 쓰면 안된다.
Caused by: org.hibernate.HibernateException: Found shared references to a collection: com.vine.cm.contents.revision.Revision.metaDatas
at org.hibernate.engine.Collections.processReachableCollection(Collections.java:186)
at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:60)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:124)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:84)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:78)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:161)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:997)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1590)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:306)
at org.springframework.orm.hibernate3.HibernateTemplate$36.doInHibernate(HibernateTemplate.java:1065)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
... 64 more
at org.hibernate.engine.Collections.processReachableCollection(Collections.java:186)
at org.hibernate.event.def.FlushVisitor.processCollection(FlushVisitor.java:60)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:124)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:84)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:78)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:161)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:997)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1590)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:306)
at org.springframework.orm.hibernate3.HibernateTemplate$36.doInHibernate(HibernateTemplate.java:1065)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
... 64 more
예를 들어보자. 다음과 같은 영속 객체가 있고, 객체의 컬렉션 형태의 데이타를 다른 객체로 복사하려고 할 경우
public class Revision {
...
private Map<Meta, string> metaDatas = new HashMap<Meta, string>();
...
}
public void testCopy() {
// 영속 객체 가져오기
Revision revision1 = dao.getRevision(1);
Revision revision2 = dao.getRevision(2);
copy(revision1, revision2);
}
...
private Map<Meta, string> metaDatas = new HashMap<Meta, string>();
...
}
public void testCopy() {
// 영속 객체 가져오기
Revision revision1 = dao.getRevision(1);
Revision revision2 = dao.getRevision(2);
copy(revision1, revision2);
}
다음과 같이 하면 org.hibernate.HibernateException: Found shared references to a collection: .. 와 같은 예외가 발생한다.
public copy(Revision revision1, Revision revision2) {
revision2.setMetaDatas(revision1.getMetaDatas()); // ERROR
}
revision2.setMetaDatas(revision1.getMetaDatas()); // ERROR
}
따라서 다음과 같은 방법으로 deep copy 를 해야한다.
public copy(Revision revision1, Revision revision2) {
for(Map.Entry<Meta, String> entry : revision1.getMetaDatas.entrySet()) {
revision2.getMetaDatas().put(entry.getKey(), entry.getValue());
}
}
for(Map.Entry<Meta, String> entry : revision1.getMetaDatas.entrySet()) {
revision2.getMetaDatas().put(entry.getKey(), entry.getValue());
}
}
이 글은 스프링노트에서 작성되었습니다.