Hibernate 2nd level cache objects that are lazy=false, result in a default fetch=join, is it documented anywhere?

半城伤御伤魂 提交于 2020-01-01 05:27:09

问题


I experience the following apparently undocumented issue, and I want to understand if

  1. I did something wrong
  2. Did anyone encounter the same issue?
  3. Is it really not documented anywhere? or did I miss something?

The behavior is this Assume the following mapping

<class name="org.sample.Foo" table="foo">
    ...
   <many-to-one name="bar" class="org.sample.Bar"/>
</class>


<class name="org.sample.Bar" table="bar" lazy="false">
    ...
</class>

First, as a background, Hibernate default value for the fetch attribute on a many-to-one relation should be "select", this is at least what is documented (I'll add the link here when I find it)

However, this is apparently only true if the referenced class is lazy="true"!

so apparently the above mapping is translated into this (because Bar is lazy="false"):

<class name="org.sample.Foo" table="foo">
    ...
   <many-to-one name="bar" class="org.sample.Bar" *fetch="join" />
</class>


<class name="org.sample.Bar" table="bar" lazy="false">
    ...
</class>

Now why would that be an issue? instead of 2 selects, Hibernate will load the non lazy reference in a single select with its "parent" (load Foo with Bar in a single select)

this actually makes sense, since the object is not lazy, why not load it?

The answer is this: what happens if Bar is in the 2nd level cache?

<class name="org.sample.Foo" table="foo">
    ...
   <many-to-one name="bar" class="org.sample.Bar" *fetch="join" />
</class>


<class name="org.sample.Bar" table="bar" lazy="false">
    <cache usage="transactional" />
    ...
</class>

And the answer to that is - nothing changes!

Apparently one would assume Hibernate is smart enough to understand that objects of this type should not be loaded, but since the default fetch was changed from select to join, Hibernate doesn't have a choice (you can't join a real table with the 2nd level cache, yet)

so Hibernate does what it is told, and uses a join to fetch an object from the database where it is already in the 2nd level cache

The solution I found is to literally change the mapping to fetch="select"

Now when the second select for Bar is about to go, Hibernate understands it should not go to the database, and fetches it from the cache. and only 1 query will execute (after warmup)


回答1:


I encountered the same issue, and found myself marking all many-to-one relations that will be cached as fetch="select". At the time when the query is built up, Hibernate cannot know whether the requested instance of Bar is in the second level cache or not (assuming that Foo is not in cached).



来源:https://stackoverflow.com/questions/1968767/hibernate-2nd-level-cache-objects-that-are-lazy-false-result-in-a-default-fetch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!