在相关实体上发生 ConstraintViolation 后 Hibernate 对象分离
Posted
技术标签:
【中文标题】在相关实体上发生 ConstraintViolation 后 Hibernate 对象分离【英文标题】:Hibernate Object Detached after a ConstraintViolation on a related entity 【发布时间】:2013-04-23 03:18:37 【问题描述】:我使用 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);
现在的问题,我有 -
我正在读取一个包含相关实体数据的文件,在数据库中创建了几条记录。这样做时,我需要设置父引用。我不想每次插入子记录时都查找父实体。所以我创建了所有父记录的列表并保留了父实体的映射(这个集合相当小,不到 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 期间没有异常,一切正常。
那么问题是什么,解决方案是什么?
感谢任何帮助。
【问题讨论】:
【参考方案1】:我不想显式验证传入的数据,而是想使用已在实体上设置的 JPA 验证
这就是你的问题所在。 The documentation 明确表示:
如果 Session 抛出异常,包括任何 SQLException,立即回滚数据库事务,调用 Session.close() 并丢弃 Session 实例。 Session 的某些方法不会使会话保持一致状态。 Hibernate 抛出的任何异常都不能被视为可恢复的。通过在 finally 块中调用 close() 确保 Session 将被关闭。
【讨论】:
就我而言,我猜这个异常是由 Hibernate 验证器 pre-perist 抛出的。所以它不完全是一个 SQL 异常,因为 JSR 303 验证将在 hibernate 尝试持久之前启动。不是吗?在那种情况下,会话状态根本不应该受到影响?在 bean 上设置所有约束听起来不太合乎逻辑,仅使用 bean 验证器最终手动调用验证器只是因为您想从异常中恢复并继续? 文档说“包括任何 SQLException”。它没有说“排除除 SQLExceptions 之外的所有异常”。实体上的 JSR-303 验证必须被视为数据库中的智能检查约束。您使用它们来使 sre 数据库不包含垃圾,但这是最后的验证,它不应该阻止您之前验证数据,并且会迫使您回滚。您当然可以忽略文档中的内容。但是,如果它不起作用,请不要抱怨。以上是关于在相关实体上发生 ConstraintViolation 后 Hibernate 对象分离的主要内容,如果未能解决你的问题,请参考以下文章