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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/82429/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 10:59:00  来源:igfitidea点击:

When Hibernate flushes a Session, how does it decide which objects in the session are dirty?

javahibernatesessionormflush

提问by tgdavies

My understanding of Hibernate is that as objects are loaded from the DB they are added to the Session. At various points, depending on your configuration, the session is flushed. At this point, modified objects are written to the database.

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

How does Hibernate decide which objects are 'dirty' and need to be written?

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

Do the proxies generated by Hibernate intercept assignments to fields, and add the object to a dirty list in the Session?

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

Or does Hibernate look at each object in the Session and compare it with the objects original state?

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

Or something completely different?

或者完全不同的东西?

回答by Matt Quail

Hibernate does/can use bytecode generation (CGLIB) so that it knows a field is dirty as soon as you call the setter (or even assign to the field afaict).

Hibernate 确实/可以使用字节码生成(CGLIB),因此只要您调用 setter(甚至分配给字段 afaict),它就会知道字段是脏的。

This immediately marks that field/object as dirty, but doesn't reduce the number of objects that need to be dirty-checked during flush. All it does is impact the implementation of org.hibernate.engine.EntityEntry.requiresDirtyCheck(). It stilldoes a field-by-field comparison to check for dirtiness.

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

I say the above based on a recent trawl through the source code (3.2.6GA), with whatever credibility that adds. Points of interest are:

我说以上是基于最近对源代码 (3.2.6GA) 的搜索,并增加了任何可信度。兴趣点是:

  • SessionImpl.flush()triggers an onFlush()event.
  • SessionImpl.list()calls autoFlushIfRequired()which triggers an onAutoFlush()event. (on the tables-of-interest). That is, queries can invoke a flush. Interestingly, no flush occurs if there is no transaction.
  • Both those events eventually end up in AbstractFlushingEventListener.flushEverythingToExecutions(), which ends up (amongst other interesting locations) at flushEntities().
  • That loops over every entity in the session (source.getPersistenceContext().getEntityEntries()) calling DefaultFlushEntityEventListener.onFlushEntity().
  • You eventually end up at dirtyCheck(). That method does make some optimizations wrt to CGLIB dirty flags, but we've still ended up looping over every entity.
  • SessionImpl.flush()触发一个onFlush()事件。
  • SessionImpl.list()autoFlushIfRequired()触发onAutoFlush()事件的调用。(在兴趣表上)。也就是说,查询可以调用刷新。有趣的是,如果没有事务,则不会发生刷新。
  • 这两个事件最终都以 结束,最终AbstractFlushingEventListener.flushEverythingToExecutions()(在其他有趣的位置中)结束于flushEntities()
  • 这会遍历 session( source.getPersistenceContext().getEntityEntries()) 调用中的每个实体DefaultFlushEntityEventListener.onFlushEntity()
  • 您最终会在dirtyCheck(). 该方法确实对 CGLIB 脏标志进行了一些优化,但我们仍然最终循环遍历每个实体。

回答by alasdairg

Hibernate takes a snapshot of the state of each object that gets loaded into the Session. On flush, each object in the Session is compared with its corresponding snapshot to determine which ones are dirty. SQL statements are issued as required, and the snapshots are updated to reflect the state of the (now clean) Session objects.

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

回答by Jeroen Wyseur

Take a look to org.hibernate.event.def.DefaultFlushEntityEventListener.dirtyCheck Every element in the session goes to this method to determine if it is dirty or not by comparing with an untouched version (one from the cache or one from the database).

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

回答by Vlad Mihalcea

Hibernate default dirty checking mechanismwill traverse current attached entities and match all properties against their initial loading-time values.

Hibernate 默认的脏检查机制将遍历当前附加的实体并将所有属性与其初始加载时间值进行匹配。

You can better visualize this process in the following diagram:

您可以在下图中更好地可视化此过程:

Default automatic dirty checking

默认自动脏检查

回答by tom

These answers are incomplete (at best -- I am not an expert here). If you have an hib man entity in your session, you do NOTHING to it, you can still get an update issued when you call save() on it. when? when another session updates that object between your load() and save(). here is my example of this: hibernate sets dirty flag (and issues update) even though client did not change value

这些答案是不完整的(充其量 - 我不是这里的专家)。如果你的会话中有一个 hib man 实体,你什么都不做,当你调用 save() 时你仍然可以获得更新。什么时候?当另一个会话在您的 load() 和 save() 之间更新该对象时。这是我的示例:即使客户端没有更改值,hibernate 也会设置脏标志(并发布更新)