我使用Spring / JPA / Hibernate。我有一个相当标准的Dao和Service层实现。
class GenericDao<T> {
public save(T entity) {
if (!entity.isIdSet()) {
getEntityManager().persist(entity);
}
// other cases are update,
// so a transactional service method will suffice
// we dont need to do anything
}
}
class ParentEntity {
// Nothing special here, just an entity with auto-generated PK, if that matters
}
class RelatedEntity {
// Fairly standard many-to-one relation
@Column(name = "parent_id",nullable = false,insertable = false,updatable = false)
public Integer getParentId() {
return parentId;
}
@NotNull
@JoinColumn(name = "parent_id", nullable = false)
@ManyToOne(cascade = {PERSIST, MERGE}, fetch = LAZY)
public ParentEntity getParent() {
return parent;
}
}
class Repository<T> { // There is an implementation of this for both entities above
@Transactional
public void save(T entity) { getDao().save(entity); }
}
现在出现问题,我正在 -
我正在读取一个包含RelatedEntity数据的文件,在数据库中创建了几条记录。在这样做时,我需要设置父引用。每次插入子记录时我都不想查找父实体。所以我创建了一个包含所有父记录的列表并保留了父实体的映射(这个集很小,小于10)。我遍历数据并在子项中设置父引用并保存子项。
public void getParentList {
List parentList = parentRepository.find();
// create a map with the list items for easy lookup on name
}
public void importData() {
for (line : file) {
RelatedEntity re = new RelatedEntity();
re.setParent(map.get(line.parentName)); // The refered object is got once in getParentList
// lookup the map for the parent
// set all properties of re here
childRepository.save(re);
}
}
到目前为止,一切都很顺利。
我不想显式验证传入数据,而是想使用已在实体上设置的JPA验证。所以我想在save()周围处理约束语音异常,并忽略不验证的记录。但是想继续使用剩下的数据。
当我这样做时,我得到一个例外:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.myads.domain.ParentEntity
public void importData() {
for (line : file) {
RelatedEntity re = new RelatedEntity();
// lookup the map for the parent
// set all properties of re here
try {
childRepository.save(re);
} catch (CVE cve) {
// log the record that failed validation
/*************
// Note: If I land here on line(x), I get PersistenceException on save for the
// next iteration(x+1).
**************/
}
}
}
当子实体抛出持久性异常时,看起来父节点实体与会话分离。如果在孩子的perist期间没有例外,一切正常。
那么问题是什么,解决方案是什么?
感谢任何帮助。
答案 0 :(得分:0)
我不想显式验证传入数据,而是想使用已在实体上设置的JPA验证
这就是你的问题所在。 The documentation明确地说:
如果Session抛出异常(包括任何SQLException),则立即回滚数据库事务,调用Session.close()并丢弃Session实例。 Session的某些方法不会使会话保持一致状态。 Hibernate抛出的异常都不能被视为可恢复的。确保通过在finally块中调用close()来关闭Session。