[JAVAEE-JPA] Performance optimization: 4 ways to trigger lazy loading __java

Source: Internet
Author: User

In a JPA application, the performance of the application can be improved by lazy loading. This is no doubt, but lazy load does not mean not to load, at some point or need to load the data, then how to trigger this loading behavior can be more effective.

Here I would like to say a little digression, the interview I will also look at the interviewee's opinion of jpa/hibernate, the answer usually contains a jpa/hibernate of some "disdain", such as jpa/hibernate performance too much food, Now the main persistence layer framework is mybatis and so on. And then I will try to get them to analyze why it is slow, some people do not know how to answer, the answer is very slow, others may use a little more experience, then answer the JPA Provider (such as hibernate) will generate very inefficient SQL, So it looks like the performance is not. If you go further, ask how to improve these inefficient SQL. It's even rarer to talk about a 123. So I think a lot of people actually give a less-than-appropriate conclusion before delving into JPA. Each technology has its own advantages and disadvantages, the perfect technology does not exist. Concrete analysis of specific problems, do not parrot is a developer should have the basic ability. Of course, I am not the priest of JPA, JPA in the current Internet mass Data environment, there are indeed a lot of problems, the most typical for example, for data fragmentation, the lack of support on the sub-table. I think that's what makes MyBatis a mainstream choice for the current Internet company. However, not all applications have such a large amount of data, and not all projects need to be divided into tables. More small and medium sized projects, if the reasonable use of JPA, development efficiency and project service can definitely not bad. After all, JPA, as part of the Java EE Standard, can be a waste of fame.

So, this article I want to start by triggering lazy load this angle, analyze several different implementations, to see how to improve the performance of the application. 0. Assumptions about Data Association relationships

Before you analyze the 4 triggering modes, let's assume a set of related relationships:

@Entity public
class Department {
    //primary key fields
    //...

    @OneToMany (mappedby = "department")
    private list<employee> employees;
}
1. Triggering by method call

This is one of the most frequently used triggers, and almost all JPA developers use this approach in general. There are even a few developers who use this approach in any situation.

As the name suggests, this method completes the trigger by invoking the methods on the Employee collection object, such as the following code:

Department Dept = em.find (Department.class, deptid);
int count = Dept.getemployees (). Size ();
// ......

By invoking the size method to trigger lazy loading, the execution of this size allows JPA's provider to generate the SQL and execute the collection data specifically. This method seems to be no problem, and in many scenarios it is really good. But it was too simple and rough. In the following two cases, a more serious performance problem is caused: the collection data volume is large. For example, the associated data has hundreds of records. There is a lot of relationship between an entity type needing to trigger lazy loading. For example, when the above department type also needs to load more one-to-many relationships.

The first situation is well understood, the greater the amount of data, the longer the SQL execution time, no doubt.
In the second case, assuming that the department type has 10 one-to-many relationships, it is now necessary to trigger lazy loading behavior to get the complete data. Then a SQL command will be generated for each relationship. Plus its own, altogether is 11 commands. Of course, your application is often not only one user in use, assuming that there are 100 users at the same time, then 1100 SQL will be executed. Is this going to be slow?

So for this type of trigger, it is possible to use it when it is determined that neither of these cases will occur. Once there is a risk of their occurrence, do not use them. 2. Trigger by join Fetch

This approach completes the correlation by adding a join fetch to the JPQL:

Query q = Em.createquery ("Select D from Department d JOIN FETCH d.employees e WHERE d.id =: id");
Q.setparameter ("id", deptid);
Department Dept = (Department) q.getsingleresult ();

This approach primarily addresses the second problem that is faced when triggered by a method call: There are too many SQL commands to execute.
When you use join fetch, there is only one SQL command executed. Therefore, the more relationships you need to trigger the load behavior, the more obvious the performance benefits of using join Fetch.

But this approach is not lucrative, and if the relationship between different business scenarios that triggers the load is not the same, there will be a lot of combinations. And the jpql of each combination is different. At this point can be combined with the actual business requirements through the concatenation of strings to complete the JPQL preparation work. This preparation is often very complicated in the case of a lot of combinations. But these problems can be overcome in comparison to the performance improvements it can bring.

In addition to providing JPQL directly, it can be used in the criteria API:

Criteriabuilder cb = Em.getcriteriabuilder ();
Criteriaquery q = cb.createquery (department.class);
Root d = q.from (Department.class);
D.fetch ("Employees", Jointype.inner);
Q.select (d);
Q.where (Cb.equal (D.get ("id"), deptid));
Department Dept = (Department) em.createquery (q). Getsingleresult ();

This approach is only to define the query in a different way, at the performance level and directly write JPQL is the same. 3. Triggered by Namedentitygraph

This approach is actually a new feature in JPA 2.1. It also allows you to perform lazy loading triggers. Let's take a look at how to define a named Entitygraph, or Namedentitygraph. From the name of the way, is not very close to namedentityquery. So they are very close to the way they are defined:

@Entity
@NamedEntityGraph (name = "graph. Department.employees ", 
      attributenodes = @NamedAttributeNode (" Employees ")) public
class Department {
    // ......
}

Use it to load the relationship:

Entitygraph graph = em.getentitygraph ("graph. Department.employees ");
map<string, object> props = new hashmap<> ();
Props.put ("Javax.persistence.fetchgraph", graph);
Department Dept = em.find (Department.class, deptid, props);

At this point the query gets the Department object that contains the employee collection we need. Similarly, only one SQL command will be generated and executed when using this method.

But in the case of a lot of combinations, as with join fetch, you need to do some preparation based on the business scenario, but this preparation is even more cumbersome, and each combination needs to add a special @namedentitygraph annotation to define. Therefore, in the combination of a lot of time, the use of @namedentitygraph is not cost-effective. So there is the following dynamic entitygraph. 4. Triggered by dynamic Entitygraph

Dynamic entitygraph are defined in a more flexible way:

Entitygraph graph = this.em.createEntityGraph (department.class);
Subgraph employeesgraph = graph.addsubgraph ("Employees");
map<string, object> props = new hashmap<> ();
Props.put ("Javax.persistence.loadgraph", graph);
Department Dept = em.find (Department.class, deptid, props);

Dynamic entitygraph are specified by the Addsubgraph method, depending on the relationship to load. 5. The entitygraph is the same as the join fetch.

Careful students see here, may find the current introduction of the so-called entitygraph, how to join the fetch so much like it. Did you just change a vest?

Obviously, it's not that simple.

Notice the above two lines of code:

#1 loadgraph
props.put ("javax.persistence.loadgraph", graph);

#2 fetchgraph
props.put ("javax.persistence.fetchgraph", graph);

What is the specific difference between the two? I'm not going to introduce proving here. Pick the point is: loadgraph: On the basis of the definition of the original entity, define what you need to get the field/relationship Fetchgraph: Completely discard the definition of the original entity, define just what fields/relationships you need to get

Note that the above "also" and "only", express the difference between the two biggest points.

For example, if we have a name field in the Department type: loadgraph: The loaded data is name and employees fetchgraph: The loaded data is only employees

Therefore, in the use of entitygraph with fetchgraph, you can accurately complete the required data loading, it is the point of which dozen. In some business scenarios that are particularly sensitive to performance, try to get the kind of acid that just loads the data you need.

For more resources on this topic, refer to the official document conclusion

The

Analysis compares the above 4 ways to trigger lazy loading, and we should be able to tell which scenario to use in a more appropriate way. Go and try some fresh in your project.

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.