当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脏标志进行了一些优化,但是我们仍然最终遍历了每个实体。