Hibernate n+1 Problems

Source: Internet
Author: User

Hibernate often uses set, bag and other sets of 1-to-many relationship, when the entity can be obtained by the relationship between the associated object or object set out, you can also set Cacade for association update and delete. This has to say that Hibernate's ORM is doing very well, very close to Oo's usage habits.

But the database access still must consider the performance problem, after setting 1 to many this kind of relationship, the query will appear the legendary n+1 question.

  The situation that arises

One-to-many: on a side, find the N objects, then need to have n objects associated with the collection, so that an original SQL query into n+11 -side object out, also became M+
    1 ;

In fact, there are a number of workarounds for this problem in hibernate in action.

Here's a summary.

Requirements like this, I have four tables (One,two,three,four) from the one that has been associated with the foreign key to four. The structure is as follows

Now get one in the session and take the content from one to four. If the simple use of session.get to achieve this.

One one = (one) session.get (one).  Class,new Integer (1));         = One.gettwos (). iterator ();          while (Iterone.hasnext ()) {            = () iterone.next ();             = two.getthrees (). iterator ();              while (Itertwo.hasnext ()) {                = (three) itertwo.next ();                Three.getfours (). Size ();                            }        }

In this case, the one that I returned after the session was closed is the information that is available from a to four.
However, the result of this is generating a large number of SQL queries, which is a typical n+1 selects problem. If the hierarchy of systems is multiple and the number of qualifying records is many, then the SQL queries that hibernate generates for you will be unacceptable.
For this example, the SQL generated is like this

Hibernate:Selectone0_.c_one_id asc1_0_, One0_.c_one_text asc2_3_0_ fromoneone0_whereone0_.c_one_id=? Hibernate:Selecttwos0_.c_one_id asC2_1_, twos0_.c_two_id asc1_1_,twos0_.c_two_id asc1_0_, twos0_.c_one_id asc2_2_0_, Twos0_.c_two_text asc3_2_0_ fromtwos0_wheretwos0_.c_one_id=? Hibernate:Selectthrees0_.c_two_id asC2_1_, threes0_.c_three_id asc1_1_,threes0_.c_three_id asc1_0_, threes0_.c_two_id asC2_1_0_,threes0_.c_three_text asc3_1_0_ fromThree threes0_wherethrees0_.c_two_id=? Hibernate:Selectfours0_.c_three_id asC2_1_, fours0_.c_four_id asc1_1_,fours0_.c_four_id asc1_0_, fours0_.c_three_id asc2_0_0_, Fours0_.c_four_textas c3_0_0_ fromFour fours0_wherefours0_.c_three_id=? Hibernate:Selectfours0_.c_three_id asC2_1_, fours0_.c_four_id asc1_1_,fours0_.c_four_id asc1_0_, fours0_.c_three_id asc2_0_0_, Fours0_.c_four_textas c3_0_0_ fromFour fours0_wherefours0_.c_three_id=? Hibernate:Selectthrees0_.c_two_id asC2_1_, threes0_.c_three_id asc1_1_,threes0_.c_three_id asc1_0_, threes0_.c_two_id asC2_1_0_,threes0_.c_three_text asc3_1_0_ fromThree threes0_wherethrees0_.c_two_id=? Hibernate:Selectfours0_.c_three_id asC2_1_, fours0_.c_four_id asc1_1_,fours0_.c_four_id asc1_0_, fours0_.c_three_id asc2_0_0_, Fours0_.c_four_textas c3_0_0_ fromFour fours0_wherefours0_.c_three_id=? Hibernate:Selectfours0_.c_three_id asC2_1_, fours0_.c_four_id asc1_1_,fours0_.c_four_id asc1_0_, fours0_.c_three_id asc2_0_0_, Fours0_.c_four_textas c3_0_0_ fromFour fours0_wherefours0_.c_three_id=?


For such a problem, we usually use JDBC before we do it without hibernate, so we can actually do it with a SQL statement that makes 3 joins, but there's a problem with that, which is that the data in the returned resultset is very much, and it's messy, It's actually arranged in parallel from one to four. For such a result set we have to manually allude to the once object structure is also a very complex operation.
Fortunately Hibernate3 can do these things for us (once again I was shocked by the power of hibernate).
The above implementations can be implemented using criteria:

Session = sessionfactory.opensession ();         = Session.createcriteria (one.  Class);        Criteria.add (Expression.eq ("Coneid",new Integer (1)));         = (one) criteria.setfetchmode ("twos", Fetchmode.join). Setfetchmode ("Twos.threes", Fetchmode.join). SetFetchMode (" Twos.threes.fours ", Fetchmode.join). Uniqueresult ();        Session.close ();

The point here is this sentence.

Criteria.setfetchmode ("twos", Fetchmode.join)
. Setfetchmode ("Twos.threes", Fetchmode.join)
. Setfetchmode ("Twos.threes.fours", Fetchmode.join)
. Uniqueresult ();

When you set Fetchmode before using criteria, you should generate SQL statements dynamically for the criteria, so the resulting SQL is a layer of join down.
Setfetchmode (String,mode) The first parameter is association path, with "." to represent the path. This is a few specific examples and the documentation is not clearly written. I tried it a long time before I tried it out.
For this example, it takes three Setfetchmode to take the fourth floor.
The first path is twos, with two set in one. This specific to be more hbm.xml configuration to set.
The second path is twos.threes.
The third one is twos.threes.fours.
An analogy, an increase in layers.
The result of this approach is that SQL is generated as follows:

Hibernate:Selectthis_.c_one_id asC1_3_, This_.c_one_text asc2_3_3_,twos2_.c_one_id asC2_5_, twos2_.c_two_id asC1_5_, twos2_.c_two_id asc1_0_,twos2_.c_one_id asc2_2_0_, Twos2_.c_two_text asc3_2_0_, threes3_.c_two_id asc2_6_, threes3_.c_three_id asC1_6_, threes3_.c_three_id asc1_1_,threes3_.c_two_id asC2_1_1_, Threes3_.c_three_text asc3_1_1_,fours4_.c_three_id asC2_7_, fours4_.c_four_id asC1_7_, fours4_.c_four_id asc1_2_, fours4_.c_three_id asC2_0_2_, Fours4_.c_four_text asC3_0_2_ fromOnethis_ Left outer JoinTwos2_ onthis_.c_one_id=twos2_.c_one_id LeftOuterjoin three threes3_ ontwos2_.c_two_id=threes3_.c_two_id Left outer JoinFourfours4_ onthrees3_.c_three_id=fours4_.c_three_idwherethis_.c_one_id=?


It's long, but there's only one SQL statement. Performance is much better. The power of hibernate is that it automatically resultset back the returned objects into your object model. This has saved us a lot of things.

It seems that hibernate is really an intriguing framework.

source code, nothing.

Hibernate n+1 Problems and Solutions

1. using Fetch Crawl, Hibernate crawl strategy is divided into single-ended agent and collection agent's crawl strategy.

Hibernate Crawl strategy ( single-ended agent crawl strategy) :

Keeping the default is the following:

    <name= "Clazz"  cascade= "Save-update"  fetch= " Select "/>

fetch= "Select" is to send an additional select The statement fetches the current object associated entity or collection settings fetch= "join"

  <name= "Clazz"  cascade= "Save-update"  fetch= " Join "/>

Hibernate will pass select statement using an outer join to the Loader Association entity live Collection at this time lazy will expire

Hibernate Crawl Policy ( collection agent's fetch strategy) :

Keeping the default (fetch= "select") is the following:

<name= "Students"  inverse= "true">      < Column = "clazz"/>< class         = "com.june.hibernate.Student"/></set>

1) fetch= "Select" will issue a separate statement query collection

2) Set fetch= "join" with a lazy invalidation of the outer join set

3) This fetch= "Subselect" also emits a SELECT statement that fetches the associated collection of all the entity objects that were previously queried. Fetch only affects HQL queries.

2. using Map Direct search for required columns

such as: Product products and Product categories product_category two sheets, many-to-one relationship. When querying a product list

Select  as  as  as  from Product P

3. Delayed retrieval Strategy

A deferred retrieval strategy avoids unnecessary loading of associated objects that the application does not need to access.

Hibernate3 is already lazy=true by default, Lazy=true does not immediately query the associated object, and the query action occurs only when an object is required to access its properties.

4. Urgent left Outer connection search strategy

The urgent left outer connection retrieval strategy takes full advantage of SQL's outer join query function and can reduce the number of SELECT statements.

Connection fetching can be defined in the mapping file.

<namefetch= "Join" ><key column= "Customer _id "><one-to-many class=" Com.hibernate.mappings.Order "/></  set>

Or use HQL's left OUTER JOIN.

or use Setfetchmode (fetchmode.join) in a conditional query

Customer CTM = (customer) Session.createcriteria (customer.  Class)                    . Setfetchmode ("Order"). JOIN)                    . Add (Restrictions.ideq (customer_id));

Hibernate n+1 Problems

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.