Connector for spring + hibernate connection Leakage

Source: Internet
Author: User

Database Connection leaks are terrible and may directly cause the system to stop responding. In addition, data inconsistency caused by transaction management errors is also terrible. In the background system, these two problems often come together. This article will explain several situations that may cause problems when using Spring + Hibernate through case studies, and hope to help you.

The article is long. If you have encountered a problem and are eager for a solution, you can read this article first: Check whether your dao has directly used the session and change it to use the hibernateTemplate.
If you want to learn more about sessions, hibernateTemplate, and transaction, continue.

The following example is based on Struts2.3.1 + Spring3.1.1 + hibernate3.5.4. The scenario is to manage system parameters, which involves the following four categories:
Action PropertyAction
Service PropertyService/PropertyServiceImpl
DAO PropertyDAO (inherit HibernateDaoSupport)
Entity SysProperty
1. dao is called directly in Action, and getHibernateTemplate is not used
In a complex multi-layer architecture system, transaction control is more reasonable in the service, and should not be controlled by the view layer. This article assumes that you did this. Generally, the processing sequence of our code is action-> service-> dao. However, there will always be people who will break this logic and can, but pay attention to the following issues.
Assume that the Action contains the following code:
1 @ Autowired
2 private PropertyDAO propertyDAO;
3 @ Override
4 public String execute () throws Exception {
5 model = propertyDAO. get (1L );
6 return null;
7}

Here, action directly accesses the get method in dao. Because the transaction is configured in the service layer, there is no transaction control here.
Next, let's look at the get method in dao. Assume that your definition is as follows:
1 public SysProperty get (Long id ){
2 return (SysProperty) getSession (). get (SysProperty. class, id );
3}

The code is very simple. getSession is the method provided in HibernateDaoSupport of the parent class. The object Id get is used to obtain the result.
Next, let's publish the system and access the page. It seems everything is okay. But refresh the page a few times and check whether your connection pool configuration is large. Refresh the page multiple times, finally, you will find that your system has stopped responding. More directly, call the relevant API in your connection pool to check the current connection usage. You will find that the refresh is performed once, And the occupied connection is added, which is terrible.
Summary: without the control of the Transaction Manager, the session opened through getSession () will not be closed, and the database connection occupied by this session will not be released.

Next, let's look at something more terrible. Suppose your action is like this:
1 private List <Long> ids;
2 @ Override
3 public String execute () throws Exception {
4 for (Long id: ids ){
5 results. add (propertyDAO. get (id ));
6}
7 return null;
8}
9
At this time, try to input multiple IDs at a time for the request. After the request ends, check the number of connections. You will find that the number of connections that are passed in is occupied, that is to say, each get call to dao occupies an unreleasable connection.
Summary: if the transaction manager is not configured and the getSession is used directly to get the session, a new session will be created every time the getSession is used. Each session occupies a new database connection, and the session has no thread-level sharing.

2. directly call dao in Action and use getHibernateTemplate
Of course, you may not have encountered the above situation, because you will write the code in DAO as follows:
1 public SysProperty get (Long id ){
2 return getHibernateTemplate (). get (getEntityClass (), id );
3}
Is everything okay? If you only want to solve the connection leakage problem, the answer is Yes. Try multiple requests and check your connection pool status. No connection leakage occurs. Therefore, the simple and reliable method is not to directly use getSession, but to use getHibernateTemplate for corresponding operations. When you need to use session, you can use the following method:
Gethibernatetemplate(cmd.exe cute (new HibernateCallback <T> (){
Public T doInHibernate (Session session) throws HibernateException {
Query queryObject = session. createQuery (hql );
//....
}
});
But... if a connection leak occurs in your system, you may need to pay more attention to it.
In this case, the get method of Dao repeats the logic: Create a session, allocate a session connection, and close the session, release the connection occupied by the session, that is, the session will not be shared at the Thread level. Let's continue and go to the third case to further explain.

3. The Service does not properly configure the Transaction Manager.
In most cases, we will configure the Transaction Manager for the service, which may be annotated with xml or @ Transactional, but it is OK if it is not configured. See the following example:
@ Transactional
Public class PropertyServiceImpl implements PropertyService {
@ Autowired
Private PropertyDAO propertyDAO;

@ PostConstruct
Public void init (){
PropertyDAO. get (1L );
}
//
}
Of course, assume that your DAO is still written as follows:
Public SysProperty get (Long id ){
Return (SysProperty) getSession (). get (SysProperty. class, id );
}
You expect to perform some database operations after the service is initialized. You also configure the Transaction Manager for the service. Then you start the application and check the connections in the connection pool. You will find that a connection has not been released! You may decisively modify the method in dao:
Public SysProperty get (Long id ){
Return getHibernateTemplate (). get (getEntityClass (), id );
}
Then you can take it for granted that even if the transaction manager is configured, getSession () cannot be used. This is not the case.
Let's adjust the code, instead of calling the get method in dao in init, as follows:
Public SysProperty getProperty (Long id ){
Return propertyDAO. get (id );
}
Then DAO continues to use (SysProperty) getSession (). get (SysProperty. class, id), and changes the call in action:
@ Autowired
Private PropertyService propertyService;
@ Override
Public String execute () throws Exception {
Model = propertyService. getProperty (1L );
Return null;
}
Re-publish, call, check the number of connections, and find that no occupied connection exists.
Summary: if the transaction manager is correctly configured, getSession is secure.

At this time, it is clear that spring implements transaction control through AOP, And the @ PostConstruct method is not controlled by AOP, so the init method above is equal to no transaction manager.
Then let's look back, is there no problem as long as getHibernateTemplate is used in dao?
Assume that the @ PostConstruct method in the service is as follows:
@ PostConstruct
Public void init (){
SysProperty p = new SysProperty ();
P. setName ("test_property_1 ");
PropertyDAO. save (p );
}
As mentioned above, this method is not controlled by spring's Transaction Manager.
Assume that the save method in DAO is as follows:
Public void save (SysProperty o ){
GetSession (). save (o );
}
Start the application, check the number of connections, and check whether the data is stored in the database. Because we directly use getSession, the connection will not be released. As mentioned above, we will also find that the data is not stored. Of course, we can understand this, as mentioned above, the transaction manager is not configured for this method.
Summary: when the data is saved using getSession (). save (), the transaction is not automatically committed.

Now modify the save method in DAO:
Public void save (SysProperty o ){
GetHibernateTemplate (). save (o );
}
Start the application, check the number of connections, and check whether the data is stored in the database. Because we use hibernateTemplate, the connection has been released. As mentioned above, we also found that the data has been stored in the database, indicating that hibernateTemplate will automatically commit the transaction.
Summary: if the transaction manager is not configured, the transaction is automatically created and submitted during the hibernateTemplate operation.

So if you think it's okay to use hibernateTemplate, be careful with the following code:
@ PostConstruct
Public void init (){
// 1. deduct 10 thousand blocks from your account
// 2. The code here throws an exception
// 3. Add 10 thousand blocks to your account B
}
If an exception occurs in step 3 above, the data inconsistency is eventually caused because the transaction 1 has been committed, but the transaction 3 has not been executed. The consequence is as serious as the connection leakage!
In addition to @ PostConstruct, @ Transactional is invalid for other reasons. Assume that the transaction manager is configured for our service, but the following code exists:
Pubic void someServiceMethod (){
New Thread (){
Public void run (){
DoSomethingLater ();
}
}
}

Public void doSomethingLater (){
// Perform a series of Database Operations
}
Then you can verify whether doSomethingLater is controlled by the Transaction Manager. In fact, it does not. Therefore, you need to understand the mechanism of spring AOP. Otherwise, a small pitfall will lead to a disaster.
There is also a situation where you configure @ Transactional not on the class, but on the method, assuming the following code exists:
// This method does not require transaction control
Public void method1 (){
Method2 ();
}

// The following method requires transaction control
@ Transactional
Public void method2 (){
// Do something
}
Because you need to configure different transaction mechanisms for different methods, you did not configure the above class, and then you made the following call on the client: service. method1 (); will methods in method2 be managed by transactions? Sadly, no.
The preceding thread call and internal method call can be handled as follows:
@ Autowired
Private ApplicationContext context;
Public void method1 (){
PropertyService service = context. getBean (PropertyService. class );
Service. method2 ();
}
Conclusion: Pay attention to the AOP mechanism of spring.

4. Reasonably configure the Transaction Manager for the Service
Finally, I will add what will happen if the transaction manager is correctly configured. At this time, whether you use getSession or getHibernateTemplate, the results are the same, the session will be shared at the thread level, and there is only one session.

Conclusion: It's rare to get started this week to get idle and write blogs during work hours. Think about how hard it was to find yourself. Back to the topic, there is no big mistake in using getSession, because you should have correctly configured the Transaction Manager. Using hibernateTemplate can solve all connection leaks, but be careful about the transaction problems that may be hidden. In addition, it is the issue of AOP when calling internal methods in spring and the issue of transactions when creating new threads. Finally, I hope this article will help you.

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.