查询pHistory表调用Criteria.uniqueResult时触发org.hibernate.AssertionFailure异常
问题分析:查询无关表时触发CenterLog的null id Hibernate错误
这个问题我之前排查过类似的,核心原因其实和你查询的pHistory表无关,问题出在Hibernate Session的自动刷新机制上,咱们一步步说清楚:
为什么会出现这个错误?
你说得没错,uniqueResult()本身确实不会主动执行保存操作,但Hibernate在执行查询前会触发自动Flush(刷新),目的是保证查询结果和Session缓存中的数据一致。如果当前Session缓存里存在一个未正确持久化的CenterLog实例——也就是处于Transient状态(没设置主键ID、还没被保存到数据库)的对象,Hibernate会尝试把它同步到数据库,这时候因为id为null,就会抛出你看到的AssertionFailure错误。
可能的触发场景
- 你在执行
pHistory查询之前的代码里,创建了CenterLog实例,但既没给它设置主键,也没调用save()/persist()方法,可这个实例已经被Session缓存接管了(比如被其他已经持久化的对象关联引用,或者不小心被加到了Session里)。 - 或者你的实体映射里有隐藏的关联关系,虽然你觉得
pHistory和CenterLog没关系,但可能通过其他实体间接关联,导致Session在查询时加载了未处理的CenterLog实例。
解决办法
针对这个问题,你可以从这几个方向入手:
- 清理无效的Session缓存:如果这个
CenterLog实例根本不需要保存,直接调用session.evict(centerLogInstance)把它从Session缓存中移除,这样自动Flush的时候就不会处理它了。 - 正确处理实体持久化:如果确实需要保存
CenterLog,那在执行查询前,要么给它设置好主键,要么确保你的实体配置了自动生成主键(比如用@GeneratedValue注解),然后调用save()/persist()完成持久化操作。 - 手动控制Flush模式:可以把Session的Flush模式改成
MANUAL,这样Hibernate不会自动触发Flush,只有你手动调用session.flush()时才会同步数据。不过这个方式要谨慎用,可能会导致查询结果和缓存不一致:session.setFlushMode(FlushMode.MANUAL); - 检查实体映射关系:再仔细核对一下
pHistory和CenterLog的实体类映射,看看有没有遗漏的关联(比如双向关联、或者通过第三方实体的间接关联),这些都可能导致Session加载到未处理的CenterLog实例。
内容的提问来源于stack exchange,提问作者Panadol Chong
相关产品推荐
相关产品推荐

