当Hibernate刷新Session时,它如何确定Session中的哪些对象是脏的?

时间:2020-03-05 18:58:41  来源:igfitidea点击:

我对Hibernate的理解是,当从DB加载对象时,会将它们添加到Session中。在不同的时候,根据配置,会话将被刷新。此时,已修改的对象将被写入数据库。

Hibernate如何确定哪些对象是"脏的"并且需要写入?

Hibernate生成的代理是否会拦截对字段的分配,并将对象添加到Session中的脏列表中?

还是Hibernate查看Session中的每个对象并将其与对象的原始状态进行比较?

还是完全不同的东西?

解决方案

回答

Hibernate会对加载到Session中的每个对象的状态进行快照。刷新时,将Session中的每个对象与其对应的快照进行比较,以确定哪些对象是脏的。将根据需要发出SQL语句,并更新快照以反映(现在干净的)Session对象的状态。

回答

看看org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck
会话中的每个元素都将通过与未修改的版本(来自缓存的一个或者来自数据库的一个)进行比较来确定该方法是否脏。

回答

Hibernate确实/可以使用字节码生成(CGLIB),以便它在调用setter(甚至分配给字段faict)后就知道该字段是脏的。

这会立即将该字段/对象标记为脏,但不会减少刷新期间需要进行脏检查的对象的数量。它所做的一切都会影响org.hibernate.engine.EntityEntry.requiresDirtyCheck()的实现。它仍然进行逐场比较以检查是否脏污。

我说的是以上内容基于最近对源代码(3.2.6GA)进行的跟踪,并添加了任何可信度。兴趣点是:

  • SessionImpl.flush()会触发onFlush()事件。
  • SessionImpl.list()调用autoFlushIfRequired()触发onAutoFlush()事件。 (在兴趣表上)。也就是说,查询可以调用刷新。有趣的是,如果没有事务,则不会发生刷新。
  • 这两个事件最终都在" AbstractFlushingEventListener.flushEverythingToExecutions()"中结束,并在" flushEntities()"处终止(在其他有趣的位置中)。
  • 这会遍历会话中的每个实体(source.getPersistenceContext()。getEntityEntries()),并调用DefaultFlushEntityEventListener.onFlushEntity()
  • 我们最终会在dirtyCheck()中结束。该方法确实对CGLIB脏标志进行了一些优化,但是我们仍然最终遍历了每个实体。