Hibernate 3 Depth Analysis--Suchunbo

Source: Internet
Author: User

Hibernate 3 Depth Analysis

Hibernate, an excellent open source implementation of the Java ORM model, is now a standard that brings "the gospel" to Java developers suffering from JDBC. Fast version updates, as developers think, Hibernate's development team is a companion to our developers. With the growing user base of Hibernate, Hibernate function has become more powerful and strong, the following for our more common and concerned about some of the content to do some more in-depth discussion, our purpose is not only flexible application, but also know the reason why, do not require everyone must Hibernate principle is very clear, but some of the good patterns, good design methods and the implementation of the important functions of the principles and methods are still helpful to us. We will explore the object relationship mapping from Hibernate, hibernate transaction processing, hibernate for a large number of processing methods and hibernate how to adjust performance according to different situations to discuss with you. Let's begin by explaining the object-relational mapping of Hibernate.

Deep Exploration One (Hibernate Object relational mapping)

First we create a new Java project, named Hibernate-deep-research. We know that there are now a lot of tools for Java objects to be generated through datasheets, such as the hibernatetools of Jboss tools, and so on, choose your familiar, all the same, in order to better grasp the basic knowledge, this article did not use these tools, the first step we completed Hibernate configuration file-Hibernate.cfg.xml, the file contents are shown in Listing 1:

List 1.hibernate.cfg.xml Content
 <?xml version= "1.0" encoding= "Utf-8"?> <! DOCTYPE hibernate-configuration Public "-//hibernate/hibernate configuration DTD 3.0//en" "http// Hibernate.sourceforge.net/hibernate-configuration-3.0.dtd "> 

From this Hibernate configuration file we can see that the database used in this article is H2, so we want to bring H2 jar package to this project. About the use of H2, here does not do a detailed introduction, it is HSQLDB rewrite, faster. We also need a POJO object class Test, it is noteworthy that we here mapping property set is class instead of resource, if it is resource we need to specify the HBM XML file, below we look at the Test class, POJO The detailed code for the Test class is shown in Listing 2:

Listing 2.Test Object class content
@Entity @table (name = "Test", schema = "public", Catalog = "Test") public class TEST implements java.io.Serializable {privat e int id;private String name;public Test () {}public test (int id) {this.id = ID;} public Test (int ID, String name) {this.id = Id;this.name = name;} @Id @column (name = "Id", unique = true, Nullable = false) public int getId () {return this.id;} public void setId (int id) {this.id = ID;} @Column (name = "Name", length = ten) public String GetName () {return this.name;} public void SetName (String name) {this.name = name;}}

Test this POJO class we use annotation to complete the mapping with the data table, @Entity that this is an entity class, @Table specify a mapping relationship with that data table, @Id indicate the primary key, @Column to indicate the variables in the POJO object and the word in the data table Paragraph of the corresponding relationship, of course, there are many annotation, here is not introduced. From which we can see that the test POJO class has a mapping relationship with the test table in the database, so how does this mapping relationship Hibernate be maintained? And the above Hibernate configuration file Hibernate.cfg.xml, and when and how to load it? The mapping attribute in the configuration file is some resource, some class,hibernate how to differentiate them? Where is the difference between resource and class loading? If you can answer these questions, you have a basic understanding of Hibernate object mapping relationship, you can skip this part, hehe, if you do not have a definite answer, then please continue, below we pass a test to answer the above questions. Create a new unit test class named Hibernatetestcase, inherited from TestCase, let's look at the Hibernatetestcase setUp method, the code is shown in Listing 3:

Listing 3.HibernateTestCase Code
Transaction TX;  protected void SetUp () throws Exception {  configuration cfg = new configuration ();  Cfg.configure ("/org/hibernate.cfg.xml");  Sessionfactory SF  = Cfg.buildsessionfactory ();  Session = Sf.opensession ();        tx = Session.begintransaction ();  }

Then we execute this test case and follow the execution, we will find that although we do not specify any resource files when we create the Configration instance, Hibernate automatically sets hibernate.properties as the default loading file. Where is Hibernate and how to set it? Let's take a look at the environment class, in the No. 608 line of this class there is such a code confighelper.getresourceasstream ("/hibernate.properties"), this code is The reset method of the Configration class is called, and we look back at the code in environment, as shown in Listing 4:

The code in Listing 4.Environment
Isolation_levels.put (New Integer (Connection.transaction_none), "NONE");  Isolation_levels.put (     new Integer (connection.transaction_read_uncommitted), "read_uncommitted");  Isolation_levels.put (     new Integer (connection.transaction_read_committed), "read_committed");  Isolation_levels.put (     new Integer (Connection.transaction_repeatable_read), "Repeatable_read");  Isolation_levels.put (     new Integer (connection.transaction_serializable), "SERIALIZABLE");

This code initializes the transaction isolation level, and we'll use it in the section on transactions, and here's a quick look at the impression.

Let's take a look at how Hibernate loads the configuration file we specify, and look at the getResourceAsStream method of the ConfigHelper class, as shown in Listing 5:

Listing 5.getResourceAsStream Methods
public static InputStream getResourceAsStream (string resource) {  string stripped = Resource.startswith ("/")?  Resource.substring (1): resource;  InputStream stream = null;  ClassLoader ClassLoader = Thread.CurrentThread (). Getcontextclassloader ();  if (classloader!=null) {  stream = Classloader.getresourceasstream (stripped);}  if (stream = = null) {stream = Environment.class.getResourceAsStream (Resource);}  if (stream = = null) {stream =      Environment.class.getClassLoader (). getResourceAsStream (stripped);}  if (stream = = null) {throw new Hibernateexception (resource + "not Found");}  return stream;}

First, we look at the first line of this method, its role is to remove the first "/" passed in the parameters, why to remove it, we found that no Hibernate in the default file is specified, the way is Confighelper.getresourceasstream ("/ Hibernate.properties "), the default also to add"/", how always feel hibernate a bit self-abuse tendencies, hehe, then hibernate why to remove this"/", we are looking at listing 5, the code is through the ClassLoader To process the resource file, the difference between the class and the ClassLoader load resource file, I think you must know, class processing resource file can be preceded with "/", and through ClassLoader processing resource file before there is no "/", otherwise you will never find the file. Let's take a look at the Parsemappingelement method in the Configration class, which is shown in Listing 6:

Listing 6.parseMappingElement
private void Parsemappingelement (Element mappingelement, String name) {Final Attribute resourceattribute= Mappingelement.attribute ("resource"); final attribute FileAttribute = Mappingelement.attribute ("file"); final Attribute Jarattribute = Mappingelement.attribute ("jar"); final Attribute Packageattribute = Mappingelement.attribute ( "Package"); final Attribute ClassAttribute = Mappingelement.attribute ("class"); if (resourceattribute! = null) {fin    Al String resourcename = Resourceattribute.getvalue ();    Log.debug ("Session-factory config [{}] named resource [{}] for mapping", name, resourcename); AddResource (resourcename);}    else if (fileattribute! = null) {final String fileName = Fileattribute.getvalue ();    Log.debug ("Session-factory config [{}] named file [{}] for mapping", name, FileName); AddFile (fileName);}    else if (jarattribute! = null) {final String jarfilename = Jarattribute.getvalue (); Log.debug ("Session-factory config [{}] named JAr file [{}] for mapping ", name, Jarfilename); Addjar (New File (Jarfilename));}    else if (packageattribute! = null) {final String PackageName = Packageattribute.getvalue ();    Log.debug ("Session-factory config [{}] named package [{}] for mapping", name, PackageName); Addpackage (PackageName);} else if (classattribute! = null) {final String className = Classattribute.getvalue (); Log.debug ("Session-factory config     [{}] named class [{}] for mapping ", name, className); try {addannotatedclass (Reflecthelper.classforname (ClassName));} catch (Exception e) {throw new Mappingexception ("Unable to load class [" + ClassName + "] Dec Lared in Hibernate configuration <mapping/> entry ",

This method isparseSessionFactory 方法调用,调用语句见清单 7 所示:

Listing 7. Calling the Parsemappingelement code block
if ("Mapping". Equals (Subelementname)) {  parsemappingelement (subelement, name);  }

Let's take a look at the code in Listing 6, where we know that there are five types of attributes supported by mapping, Resource,file,jar,package and class, and that when the property is class, the Addannotatedclass method is called to Class is loaded and placed in the list. Of course, there are three other ways to perform different operations, it is recommended that the condition of the judgment class mentioned behind the resource, performance will be better. At this point, Hibernate loads the resource file and the mapping relationship between the POJO and the data table. We're done, we know there are many properties in the mapping relationship, as long as you follow the above thinking to track Hibernate implementation process, everything will understand, we do not introduce each one here. Let's begin by explaining some of the knowledge about Hibernate transactions.

Back to top of page

Deep Exploration II (Hibernate's transaction management)

We know that Hiberante is a lightweight package for JDBC, and Hiberante itself does not have the ability to manage transactions,

It is the management of the transaction entrusted to the underlying JDBC or JTA to achieve the management and scheduling of things. This means that Hibernate supports two types of JDBC and JTA, so what is the difference between these two types of transactions? Hibernate's JDBC transaction is implemented based on the JDBC Connection, whose life cycle is within Connection, meaning that hibernate's JDBC transaction is not cross-Connection. While Hibernate's JTA transaction type is managed by the JTA container, the JTA container dispatches the many Connection that are currently joining the transaction and implements its transactional requirements. The JTA transaction cycle can span multiple JDBC Connection life cycles. Now that we've learned about Hibernate's transaction types, we'll track down how hibernate implements both types of transactions, let's talk about how hibernate implements JDBC transaction management. Take a look at the last second line of code in Listing 3 session = Sf.opensession (), what did Hibernate do at the open session? It first calls the Opensession method of the Sessionfactoryimpl, obtains the connection connection in the Opensession method, corresponds to the getconnection () in JDBC, and then sets the Autocommit To False, the setup code is shown in Listing 8:

Listing 8.SessionImpl Section Code
 Sessionimpl (Final Connection connection,final Sessionfactoryimpl factory,final boolean autoclose,final long timestamp, Final Interceptor Interceptor,final Entitymode entitymode,final Boolean flushbeforecompletionenabled,final Boolean Autoclosesessionenabled,final Connectionreleasemode Connectionreleasemode) {super (factory); this.rootsession = null; This.timestamp = Timestamp;this.entitymode = Entitymode;this.interceptor = Interceptor;this.listeners = Factory.geteventlisteners (); this.actionqueue = new Actionqueue (this); this.persistencecontext = new Statefulpersistencecontext (this); this.flushbeforecompletionenabled = flushbeforecompletionenabled; this.autoclosesessionenabled = Autoclosesessionenabled;this.connectionreleasemode = ConnectionReleaseMode; This.jdbccontext = new Jdbccontext (This, connection, interceptor); loadqueryinfluencers = new Loadqueryinfluencers (fact Ory); if (Factory.getstatistics (). isstatisticsenabled ()) {Factory.getstatisticsimplementor (). Opensession ();} if (LOG.isdebugenabled ()) {Log.debug ("opened session at Timestamp:" + timestamp);}} 

AutoClose Pass the value is false, in fact, this value is set in the Settings class. Then let's take a look at the last line of code in Listing 3, TX = Session.begintransaction () This line of code, first called the Sessionimpl class BeginTransaction method, the code is shown in Listing 9:

Listing 9.beginTransaction Code Snippets
Errorifclosed ();  if (rootsession! = null) {  //todo:should seriously consider not allowing a txn to ' begin from a ' child session      can always route the request to the root session  ... Log.warn ("Transaction started on non-root session");  }  Transaction result = Gettransaction ();  Result.begin ();  return result;

We mainly look at the last third and fourth lines of code, Transaction result = gettransaction () we can see that result is Org.hibernate.transaction.JDBCTransaction, then Result.begin () is called the Begin method in Jdbctransaction, and the method code is not listed here. The main function of this method is to check again if the autocommit is false, if not set to False, you can see Hibernate in the Opensession and begin transaction need to check whether the transaction is auto C Ommit's. The Drivermanagerconnectionprovider's Getconnection method is then called, as shown in Listing 10:

Listing 10.getConnection Method body
 Public Connection getconnection () throws SQLException {if (log.istraceenabled ()) log.trace ("Total checked     -out connections: "+ checkedout);   Synchronized (pool) {if (!pool.isempty ()) {int last = Pool.size ()-1; if (log.istraceenabled ()) {Log.trace ("Using pooled JDBC connection, pool size:" + last);   checkedout++;}     Connection pooled = (Connection) pool.remove (last);    if (isolation!=null) pooled.settransactionisolation (Isolation.intvalue ());    if (Pooled.getautocommit ()!=autocommit) pooled.setautocommit (autocommit);     return pooled;}}     Log.debug ("Opening new JDBC connection");     Connection conn = drivermanager.getconnection (URL, connectionprops);     if (isolation!=null) conn.settransactionisolation (Isolation.intvalue ());     if (Conn.getautocommit ()!=autocommit) conn.setautocommit (autocommit); if (log.isdebugenabled ()) {log.debug ("created connection to:" + URL + ", Isolation Level:" + Conn.gettransac Tionisolation () );} if (log.istraceenabled ()) Checkedout++;return Conn;}

From this code, it's more proof that Hibernate is just the encapsulation of JDBC, it doesn't do any extra things by itself, and by DriverManager to get the connection connection and JDBC, let's look at one of the variables in this code. Isolation, this variable we mentioned in Listing 4, is about the transaction isolation level, remember that the transaction isolation level has those? How do we set the transaction isolation level? Currently this example does not set the transaction isolation level, so the value of isolation is null, so let's take a look at the different transaction isolation levels in Listing 4 What does that mean?

Transaction_read_uncommitted means that you can read the data of uncommitted things, which is often said dirty reads; transaction_read_committed indicates that the record is not read in the database until the transaction is committed; Transaction_ Repeatable_read indicates that this record cannot be modified, but can read the records that have been added; transaction_serializable means that all cases are locked, and the transaction is executed serially, one after the other, ensuring that no dirty reads, no repetition, phantom, etc. But it pays a lot of price, the performance is not good. So how does Hibernate set the isolation level? We just need to add hibernate.connection.isolation this property to Hibernate configuration file, its value is numeric, can be set to 1,2,4,8 corresponding to the above description order. The default isolation level for different databases is not the same, so you set the database isolation level that it supports based on different databases. For the JTA transaction type you can see for yourself how Hibernate is implemented by explaining the JDBC approach. Let's start by explaining how Hibernate works with big data volumes.

Back to top of page

Deep Exploration III (Hibernate processing of large data volumes)

We often find in the project that once the amount of data to be accessed reaches an order of magnitude, the system becomes unusually slow, most of which is generated in bulk operations, and if it is simply a request sent from the user interface, this situation will not happen unless you have not applied a paging mechanism. Below we explain in detail, for this batch of, big data quantity what way to deal with. One requirement now is to require that all records older than 40 be deleted, and that the data will have 50,000, as usual, as in Listing 11:

Listing 11. Rookie-level Big Data Delete method
Iterator it = Session.createquery ("From Employee where Age >40"). Iterate ();  while (It.hasnext ()) {       Employee employee = (employee) it.next ();       Session.delete (employee);  }    Tx.commit ();    Session.close ();

We will find that the above operation Hibernate executes a large number of SQL statements, and these objects are persisted, in addition to consuming a lot of memory, execution is still quite slow, some people say, we can use the evict method ah, every time after the deletion of the memory of persistent objects to clean out, good, You can do this, which solves the problem of consuming a lot of memory, but if you track Hibernate execution, and you find that a lot of SQL statements are still there, is there a way to delete more than 50,000 records by just executing a single statement? Of course, let's take a look at Hibernate3 to provide me with the bulk operation method, the revised code is shown in Listing 12:

The bulk operation method provided by the inventory 12.hibernate3
int it = session.createquery ("Delete Employee where Age >40"). Executeupdate ();

This approach avoids the two drawbacks presented above, and we look at how hibernate is going to do this, looking at the Execute method of the Basicexecutor class that hibernate comes with, as shown in Listing 13:

Execute method fragment for listing 13.BasicExecutor
st = Session.getbatcher (). preparestatement (SQL);  Iterator parameterspecifications = This.parameterSpecifications.iterator ();  int pos = 1;  while (Parameterspecifications.hasnext ()) {  final parameterspecification Paramspec =      ( parameterspecification) Parameterspecifications.next ();  pos + = Paramspec.bind (St, parameters, Session, POS);}  if (selection! = null) {  if (selection.gettimeout () = null)     {st.setquerytimeout (Selection.gettimeout (). Intva Lue ());}}  return St.executeupdate ();  }

This code is not a familiar feeling, hehe, that shows you JAVA Foundation can also, indeed the above code and we first use the JDBC API to manipulate the bulk data is the same way.

Back to top of page

Deep Exploration Four (Hibernate performance tuning)

We know that Hibernate 3 has removed the Find method, and the reason for this is that performance issues are taken into account. Because the Find method is not read-only for the cache, performance is poor, if you are useful to Hibernate version 3 earlier, be careful.

Hibernate 3 in the normal case of persistent objects will load the properties of the object all come in, even if some large objects we do not use. Because lazy load properties only work at the class level, Hibernate 3 allows us to apply lazy loading at the attribute level so that you can have the properties of the selected loaded object. The setting is also simple, just add @Basic (fetch = Fetchtype.lazy) to the property's Get method, and then we need to enhance the class, with the Ant script to strengthen it, very simply, do not give the code, otherwise the added comment will be ignored. If you are using the HBM format to map the file, then add Lazy=true to the property line. The above-mentioned is the attribute-level lazy loading, class-level delay loading people also have to be flexible to apply, after all, it is very helpful to improve performance.

We also mentioned above about the big data cache problem, mentioned for those infrequently used data to clean up the cache in a timely manner, we can use the clear or evict method of the session, develop good habits, save the performance bottleneck in the event of blindness. Some tools for monitoring performance you can do it yourself, such as LoadRunner and so on are very good.

Back to top of page

Summarize

This article through a new Java engineering Hibernate-deep-research, and then through an example to guide you to hibernate 3 on object mapping, transaction management, large data volume and other aspects of the principles and implementation process, Each time the revelation is done through a simple test unit. By tracking the Hibernate execution process and sharing the mysteries with you, you can make it clearer and easier to understand through examples. We know that it is impossible to explain all aspects of Hibernate in detail in just one article. This article provides the most basic, the most fundamental explanation of the development process, any complex transaction in the final analysis or from the foundation, there is a sentence to say, "to give the fish, rather than to teach the fishing", I think as long as the direction of the right, know how to start, there will not be a big mistake, and finally wish everyone work smoothly

Hibernate 3 Depth Analysis--Suchunbo

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.