The hibernate delay loading technique is described in this paper. Share to everyone for your reference, specific as follows:
Hibernae delay Loading is a very common technique in which the collection properties of an entity are deferred loaded by default, and the entities associated with entities are deferred loaded by default. Hibernate can reduce the memory overhead of the system through this delay loading, so as to ensure the performance of Hibernate.
The following is the first to dissect the "secret" of Hibernate delay loading.
Deferred loading of collection properties
When Hibernate Initializes a persisted entity from the database, does the collection property of the entity initialize with the persisted class? If the collection attribute contains 100,000 or even millions of records, the ability to crawl all the collection properties while initializing the persisted entity will result in a steep performance drop. It is entirely possible that the system only needs to use some of the records in the persisted class collection properties, not all of the collection properties, so that all collection properties are not necessary to be loaded at once.
For collection properties, it is often recommended that you use a deferred load policy. Deferred loading is when the system needs to use collection properties to load the associated data from the database.
For example, the following person class holds a collection property, the type of the element in the collection property is address, and the code fragment for the person class is as follows:
Listing 1. Person.java
public class person
{
//Identity attribute
private Integer ID;
The person's Name property is
private String name;
The age attribute of the person is reserved
private int age;
Use set to save collection properties
Private set<address> addresses = new hashset<address> ();
The setter and getter methods for each property are omitted below
...
}
In order for Hibernate to manage the collection properties of the persisted class, the program provides the following mapping file for the persisted class:
Listing 2. Person.hbm.xml
<?xml version= "1.0" encoding= "GBK"?> DOCTYPE hibernate-mapping Public "-//hibernate/hibernate mapping DTD 3.0//en" "http://www.hibernate.org/dtd/ Hibernate-mapping-3.0.dtd ">
From the code that maps the file above, you can see that the address class in the collection property of person is just an ordinary POJO. The address class contains detail, zip two properties. Because the address class code is very simple, the code for that class is no longer given.
The code in the <set.../> element of the above mapping file specifies lazy= "true" (lazy= "true" is the default value for <set.../> elements), which specifies that Hibernate will delay loading the collection properties The Address object.
For example, you can load a person entity with ID 1 by using the following code:
Session session = Sf.getcurrentsession ();
Transaction tx = Session.begintransaction ();
Person P = (person) session.get (Person.class, 1); <1>
System.out.println (P.getname ());
The above code simply requires access to the person entity with ID 1 and does not want to access the address object that this person entity is associated with. There are two things at this point:
1. If you do not delay loading, Hibernate immediately crawls the address object associated with the person entity when it loads the corresponding data record.
2. If deferred loading is used, Hibernate only loads the corresponding data records for the person entity.
Obviously, the second approach reduces the interaction with the database and avoids the memory overhead of loading the address entity-which is why Hibernate defaults to enable deferred loading.
The question now is, how exactly is delay loading implemented? Hibernate What is the addresses property value of the person entity when loading the person entity?
To solve this problem, we set a breakpoint at the <1> code and Debug in Eclipse, and you can see the output in Eclipse's Console window as shown in Figure 1:
Figure 1. Lazy load Console output for collection properties
As you can see in Figure 1 output, Hibernate only captures data from the data table corresponding to the person entity, and does not crawl data from the data table corresponding to the Address object, which is deferred loading.
So what is the addresses attribute of the person entity? You can see the results shown in Figure 2 from the Eclipse's Variables window at this point:
Figure 2. Deferred-loaded collection property values
As you can see from the box in Figure 2, this addresses property is not an implementation class that we are familiar with HashSet, TreeSet, but a Persistentset implementation class, a implementation class that Hibernate provides for the Set interface.
The Persistentset collection object does not really crawl the data of the underlying data table, so naturally it cannot initialize the address object in the collection. However, the Persistentset collection holds a session attribute, which is Hibernate sessions, and when the program needs to access the Persistentset collection element, Persistentset takes advantage of the SES Sion property to crawl the actual address object corresponding to the data record.
What about capturing the corresponding data records of those address entities? This is also difficult to persistentset, because the Persistentset collection also has an Owner property, which explains the address object belongs to the person entity, Hibernate will go to find the address corresponding Datasheet foreign key value reference to The data for the person entity.
For example, if we click the addresses row in the window shown in Figure 2, which tells Eclipse to debug and output the Addresses property, and that is to access the Addresses property, you can see the output of SQL in the Console window of Eclipse as follows Sentence
Select
addresses0_.person_id as person1_0_0_,
Addresses0_.detail as detail0_,
Addresses0_.zip as zip0_
from
person_address addresses0_
where
addresses0_.person_id=?
This is the Persistentset collection and the SQL statement that captures a particular address record according to the owner attribute. You can now see the output shown in Figure 3 from the Eclipse's Variables window:
Figure 3. Loaded Collection Property values
As you can see from Figure 3, the addresses attribute has been initialized, and the collection contains 2 address objects, which are the two address objects associated with the person entity.
As can be seen from the above, Hibernate for Set property delay loading is the Persistentset implementation class. When deferred loading, the start Persistentset collection does not hold any elements. But Persistentset will hold a Hibernate session, which guarantees that when the program needs to access the collection "immediately" to load the data records and mount the collection elements.
Similar to the Persistentset implementation class, Hibernate also provides implementation classes such as Persistentlist, Persistentmap, Persistentsortedmap, Persistentsortedset, and so on. Their functions are roughly similar to those of Persistentset.
Familiar with Hibernate collection properties readers should remember that Hibernate requires declaring collection properties only with sets, lists, maps, SortedSet, SortedMap, and so on, instead of HashSet, ArrayList, HashMap, TreeSet, TreeMap, and so on, because the Hibernate need to delay loading the collection properties, and Hibernate delay loading is dependent on Persistentset, persistentlist, Persistentmap , Persistentsortedmap, Persistentsortedset-that is to say, the Hibernate layer needs to use its own collection implementation class to complete the deferred loading, so it requires the developer to use a collection interface, Instead of a collection implementation class to declare a collection property.
Hibernate the collection property defaults to deferred loading and, in some special cases, sets the lazy= "false" property for the <set.../>, <list.../>, <map.../>, and so on to cancel the delay load.
Deferred loading of associated entities
By default, Hibernate also uses deferred loading to load the associated entities, whether One-to-many, one-to-one, Many-to-many, Hibernate default is deferred loading.
For an associated entity, you can divide it into two situations:
1. The associated entity is multiple entities (including One-to-many, Many-to-many): At this point the associated entity will be in the form of a collection, and Hibernate will use Persistentset, Persistentlist, Persistentmap, A collection of Persistentsortedmap, Persistentsortedset, and so on to manage deferred-loading entities. This is the scenario described earlier.
2. The associated entity is a single entity (including One-to-one, many-to-many): When Hibernate loads an entity, the deferred associated entity is a dynamically generated proxy object.
When the associated entity is a single entity, that is, the case where the associated entity is mapped using <many-to-one.../> or <one-to-one.../>, these two elements can also specify deferred loading through the lazy property.
The following example maps the address class to a persisted class, at which point the address class becomes an entity class, and the person entity forms a One-to-many two-way association with the address entity. The mapping file code at this point is as follows:
Listing 3. Person.hbm.xml
<?xml version= "1.0" encoding= "GBK"?> <!--specify Hibernate DTD information--> DOCTYPE hibernate-mapping Public "-//hibernate/hibernate mapping DTD 3.0//en" "http://www.hibernate.org/dtd/ Hibernate-mapping-3.0.dtd ">
The program then loads the person entity with ID 1 by using the following code fragment:
Opens the context-related session sessions Session
= Sf.getcurrentsession ();
Transaction tx = Session.begintransaction ();
Address: Session.get (Address.class, 1); <1>
System.out.println (Address.getdetail ());
To see the processing of its associated entities when Hibernate loads the address entity, we set a breakpoint at the <1> code and Debug in Eclipse, and you can see the following SQL statement output from the Eclipse's Console window:
Select
address0_.address_id as address1_1_0_,
Address0_.detail as detail1_0_,
Address0_.zip as zip1_0_,
address0_.person_id as person4_1_0_
from
address_inf address0_
where
Address0_.address_ Id=?
It is not difficult to see from this SQL statement, Hibernate Load address entity corresponding data table crawl record, not from the person entity corresponding data table crawl record, this is delayed loading play a role.
See the output from Eclipse's Variables window as shown in Figure 4:
Figure 4. Deferred-loaded entities
As you can see clearly in Figure 4, the person entity associated with the address entity is not a person object, but an instance of a Person_$$_javassist_0 class that is dynamically generated by Hibernate using Javassist projects Hibernate-When the associated entity is delayed to load, a dynamic proxy object will be generated using Javassist, which will be responsible for the agent "temporarily not loaded" associated entity.
As long as the application needs to use a "pending" associated entity, the PERSON_$$_JAVASSIST_0 proxy object is responsible for loading the real associated entity and returning the actual associated entity-the most typical proxy pattern.
Click the Person property in the Variables window shown in Figure 4 (that is, forcibly use the person property in debug mode) and see the Eclipse's Console window output the following SQL statement:
Select
person0_.person_id as person1_0_0_,
person0_.name as name0_0_,
Person0_.age as age0_0_
from
person_inf person0_
where
person0_.person_id=?
The above SQL statement is the statement to crawl the associated entity "deferred loading." You can see the results of the Variables window output shown in Figure 5:
Figure 5. Loaded entities
Hibernate uses the mode of "deferred loading" to manage the associated entity, in fact, when loading the main entity, it does not really crawl the corresponding data of the associated entity, but only dynamically generates an object as the agent of the associated entity. When an application really needs to use an associated entity, the proxy object is responsible for fetching records from the underlying database and initializing the real associated entity.
In Hibernate delay loading, the client program begins to acquire only a dynamically generated proxy object, while the real entity is delegated to the proxy object to manage-this is the typical proxy pattern.
Agent mode
Agent mode is a very broad design pattern, and when client code needs to invoke an object, the client actually does not care whether to get the object accurately, as long as it can provide an object that provides the function, and then we can return the proxy for that object.
In this design mode, the system provides a proxy object for an object, and the proxy object controls the reference to the source object. An agent is a Java object that represents another Java object to act on. In some cases, the client code does not want to or cannot invoke the callee directly, and the proxy object can mediate between the client and the target object.
To the client, it can not distinguish between proxy object and real object, it does not need to distinguish between proxy object and real object. The client code does not know the real proxy object, the client code is interface-oriented programming, it only holds a proxy object interface.
In summary, as long as the client code cannot or does not want to access the invoked object directly-there are many reasons for this, for example, you need to create a very expensive object, or the object is called on a remote host, or the target object's function is not enough to meet the requirements ... but instead create an extra proxy object to return to the client using the , then this design is the proxy mode.
The following example shows a simple proxy mode, where the program first provides an image interface, representing the interface implemented by the large picture object, which has the following interface code:
Listing 3. Image.java
Public interface Image
{
void Show ();
}
This interface provides an implementation class that simulates a large picture object that the constructor of the implementation class uses the Thread.Sleep () method to pause the 3s. The following is the program code for the Bigimage.
Listing 4. Bigimage.java
Use this bigimage to simulate a large picture public
class Bigimage implements image
{public
bigimage ()
{
try
{
//Program paused 3s mode analog overhead
Thread.Sleep (3000);
System.out.println ("Picture load succeeded ...");
}
catch (Interruptedexception ex)
{
ex.printstacktrace ();
}
}
Implementation of the show () method in Image is public
Void Show ()
{
System.out.println ("Drawing actual large picture");
}
The above program code pauses 3s, which means that creating a Bigimage object requires 3s of time overhead-a program that uses this latency to simulate the overhead of loading this picture. If you do not use proxy mode, the system will generate a 3s delay when you create Bigimage in your program. To avoid this delay, the program provides a proxy object for the Bigimage object, and the proxy class for the Bigimage class is shown below.
Listing 5. Imageproxy.java
The public class Imageproxy implements image
{
//combines an image instance as the object of the proxy as
private image image;
Use abstract entities to initialize proxy object public
imageproxy (image image)
{
this.image = image;
}
/**
* Rewrite the show () method of the Image interface *
This method is used to control access to the proxy object,
* and to be responsible for creating and deleting the proxy object
/public void show
()
{
//Only create the proxy object
if (image = = null)
{
image = new Bigimage ()
} If you really need to call the Show method of image
image.show ();
}
The Imageproxy proxy class above implements the same show () method as Bigimage, which allows the client code to use the proxy object as a bigimage after it acquires the proxy object.
The control logic is added to the show () method of the Imageproxy class, which controls the actual creation of the represented Bigimage object when the system actually calls the show () of the image. The following program needs to use the Bigimage object, but the program does not return the Bigimage instance directly, but instead returns the Bigimage proxy object first, as shown in the following procedure.
Listing 6. Bigimagetest.java
public class Bigimagetest
{public
static void Main (string[] args)
{
Long start = System.currenttimemillis ();
The program returns an image object that is just the Bigimage proxy object
image image = new Imageproxy (null);
SYSTEM.OUT.PRINTLN ("The system gets the time cost of the Image object:" +
(System.currenttimemillis ()-start));
The program will actually create the proxy object only when the show () method of the image proxy is actually invoked.
image.show ();
}
The above program initializes the image very quickly because the program does not actually create the Bigimage object, just gets the Imageproxy proxy object--until the program calls the Image.show () method, the program needs to actually invoke the show () method of the Bigimage object, the program The Bigimage object is actually created at this time. Run the above program and see the results shown in Figure 6.
Figure 6. Improve performance with Agent mode
See the results shown in Figure 6, the reader should be able to agree: Using proxy mode improves the system performance of getting Image objects. But there may be a reader to ask: The program calls the Imageproxy object's show () method as needed to create the Bigimage object Ah, the system overhead is not really reduced AH? It's just that the system overhead is delayed.
We can answer this question from the following two angles:
The creation of Bigimage is deferred until it is really needed, thus ensuring the fluency of the previous program, and reducing the Bigimage's lifetime in memory, and saving the system's memory overhead from the macro level.
In some cases, perhaps the program will never really call the show () method of the Imageproxy object-meaning that the system does not need to create bigimage objects at all. In this case, the use of proxy mode can significantly improve the performance of the system.
Exactly like this, Hibernate is also through the proxy mode to "postpone" loading the associated entity time, if the program does not need to access the associated entity, the program will not crawl the associated entities, so that both save the system memory overhead, but also can shorten the Hibernate loading entities time.
Summary
Hibernate Delay Loading (lazy load) is essentially the application of proxy mode, in the past years, we often through proxy mode to reduce the system's memory overhead, improve the operational performance of the application. Hibernate leverages this advantage of the proxy model and combines Javassist or cglib to dynamically generate proxy objects, which adds flexibility to the proxy model, Hibernate to a new name for this usage: deferred loading. In any case, the full analysis, understanding of these open source framework implementation can better feel the advantages of the classic design patterns.
I hope this article will help you with Java programming based on the Hibernate framework.