최대 절전 모드 4.1을 사용하고 있으며 개체 컬렉션에 추가 된 임시 태그 목록을 저장하려고 할 때마다 다음 예외가 발생합니다.정직하게 이해하지 못하는 TransientObjectException을 해결하는 방법
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.myapplication.domain.Tag
at org.hibernate.engine.internal.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:249)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:459)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:132)
at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:811)
이제 설명을 좀해야합니다. 내 태그 클래스에는 동의어 모음이 있습니다. 나는이 관계를 추가하기 전에,이 예외를 가진 적이 없어 모든 것이 잘 작동 :
여기<class name="com.myapplication.domain.Tag">
<id name="id" column="tag_id" type="long">
<generator class="native"/>
</id>
<property name="term" index="termIndex" unique="true" not-null="true" />
<property name="description" />
<property name="approved" />
<many-to-one name="masterTag" column="master_tag_id"
class="com.myapplication.domain.Tag" />
<bag name="synonyms">
<key column="master_tag_id" />
<one-to-many class="com.myapplication.domain.Tag" />
</bag>
</class>
객체가 태그를 매핑하는 방법입니다. Tags
클래스는 단지 구성 요소 클래스입니다. Tags.list는 Hibernate가 영속하고있는 실제 콜렉션이다.
<component name="tags">
<bag name="list" table="user_to_tag">
<key column="user_id" />
<many-to-many class="com.myapplication.domain.Tag" column="tag_id"/>
</bag>
</component>
실제로 전혀 동의어가 포함되지 않은 데이터베이스에 저장하려고 태그는, 그래서 그것을 믿지 않는 일시적인 동의어 태그와 아무 상관이있다. 나는 캐스케이드 (cascade)하기를 원하지 않습니다. 그래서 <bag>
태그에 캐스케이드 속성을 부여하지 않았습니다.
사용자는 대개 문자열 목록을 통해 시스템에 태그를 삽입합니다. 나는 태그를 포함하는 객체가 저장 될 때마다 즉석에서 태그를 만들거나 기존 태그에 링크하기를 원하기 때문에이 방법을 사용했습니다. 어쩌면 이것은 가치가있는 것보다 더 큰 문제일까요? 태그 만 연결하면 문제가 해결 될 수 있습니다. 아마 Hibernate에서의 on-the-fly 태그 생성 처리의 복잡성은 처리 할 수있는 것보다 약간 더 많을 것입니다.
이것은 새로운/기존 태그를 모두 한 번에 저장하는 데 사용하는 방법입니다. 어떤 이유로
public void saveAll(Tags tags) {
List<Tag> tagsToOverwrite = new ArrayList<Tag>();
Iterator<Tag> i = tags.getList().iterator();
while(i.hasNext()) {
Tag tag = i.next();
if(stopListService.hasWord(tag.getTerm())) {
i.remove();
} else {
if(tag.isTransient()) {
Tag dbTag = findByTerm(tag.getTerm());
if(dbTag == null) {
save(tag);
} else {
tagsToOverwrite.add(dbTag);
}
}
}
}
tags.overwriteAll(tagsToOverwrite);
}
그것은이 TransientObjectException
를 throw 할 때의 그 Tag dbTag = findByTerm(tag.getTerm());
에 실패 객체가 데이터베이스에 저장 될 때마다, 먼저 태그 컬렉션을 유지하기 위해이 방법으로 호출합니다.
public Tag findByTerm(final String term) {
Query query = getCurrentSession().createQuery(
"from Tag tag " +
"where tag.term = :term "
);
return (Tag) query
.setParameter("term", term.toLowerCase())
.setCacheable(true)
.uniqueResult(); // This is where the exception gets thrown specifically
}
나는 내가 원하는 모든 데이타베이스에서의 여부를 내가 그것을 저장하기 전에 있는지 확인 단순히 때문에이 방법은,이 예외를 슬로우 왜 확실하지 않다 :이 방법은 간단한 쿼리입니다. 내가하는 모든 일이 질의를 할 때 객체가 저장되지 않는다고 불평하는 이유는 무엇입니까?
태그 목록에 하나의 태그 만 들어 있으면이 방법이 효과적입니다. 저장할 임시 태그의 수가 2 이상일 때만 실패합니다. 예를 들어,이 실패 여기
@Test
public void saveShouldPersistTransientTags() {
User user = userRepository.find(1);
// makes list of 3 tags that are transient (id = 0)
user.getTags().setTagsAsString("training learning business");
userRepository.save(user);
flush();
user = userRepository.find(1);
assertEquals(3, user.getTags().getList().size());
}
가 UserRepository.save() 방법 :
@Override
public void save(User user) {
tagRepository.saveAll(user.getTags());
super.save(user);
}
당신은 내가 처음 과도 모든 태그를 저장하려고 참조 (또는 그들을 볼 수 있듯이 데이터베이스에 저장). 그러나 Hibernate는 결코 묻지는 않았지만 어쨌든 예외가 던져지는 위치에있는 tagRepository.saveAll(user.getTags());
콜에서 user.tags.list
콜렉션을 유지하려고합니다.
물론 Hibernate 매핑에서 synonyms
콜렉션을 제거하면이 테스트는 아무 문제없이 통과합니다.나는 synonym
수집을 활성화 할 때 그것은 단지 실패하고 그것은 단지는 learning
태그에 도달 할 때 실패합니다 (training
태그가 데이터베이스에서 발견되지 않고 잘 유지됩니다.)
어떤 생각을 왜 동의어로로 컬렉션이이 문제의 원인입니까?
시간을 절약하기 위해 곧이 문제를 파악할 수 없다면, 이런 경우에 Hibernate의 복잡성이 그렇게 좋은 것은 될 수 없으므로 JDBC를 사용하는 것이 매우 바람직합니다. 나는 이것이 행동에 주어진 버그일지도 모른다라고 생각한다. 그것은 여전히 나에게 어떤 의미가 없습니다.
이 테스트를 실행하는 코드는 동의어를 처리하지 않습니다. (태그 매핑에서 동의어 컬렉션을 제거하면 동의어가 어떻게 추가되는지 알 수 없습니다. 디버거에서 동의어 모든 3 개의 일시적인 태그에 대한 목록이 비어 있습니다. 내가 계속보고 싶습니다.이 하나가 완전히 엉망이되었습니다. – egervari
다른 모든 테스트를 주석 처리하고이 테스트 만 실행하고 어떻게 작동하는지 볼 수 있습니다. 또한 최대 절전 모드 로깅을 설정하고 – digitaljoel
예, 테스트가 100 % 격리되지 않았습니다. 모든 로그를 켜서 로그를 확인할 것입니다. 찾을 수 있기를 바랍니다. 이것이 최대 절전 모드의 버그라고 확신합니다. . 그냥 태그에 대한 봄의 JdbcTemplate을 사용하고 싶습니다. – egervari