Using Hibernate with Struts2, entire flow is as:
hibernate.cfg.xml
as:
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
<property name="connection.url">jdbc:oracle:thin:@xx.xx.xxx.xx:1521:TEST</property>
<property name="connection.username">xxxx</property>
<property name="connection.password">xxxxyyy</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<mapping class="test.models.administration.Menus" />
<mapping resource="Dual.hbm.xml" />
</session-factory>
</hibernate-configuration>
And for DAO's extending AbstractSimpleGenericDao
:
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.googlecode.s2hibernate.struts2.plugin.annotations.SessionTarget;
import com.googlecode.s2hibernate.struts2.plugin.annotations.TransactionTarget;
@SuppressWarnings("unchecked")
public abstract class AbstractSimpleGenericDao<C, I extends Serializable> {
Class<C> entityClass;
@SessionTarget
protected Session hSession;
@TransactionTarget
protected Transaction hTransaction;
{
entityClass = (Class<C>) ((ParameterizedType)
getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public List<C> getAll()
{
try
{
return hSession.createCriteria(entityClass).list();
}
catch (HibernateException e)
{
throw e;
}
}
public C get(I id)
{
try
{
return (C) hSession.get(entityClass, id);
}
catch (HibernateException e)
{
throw e;
}
}
public void save(C object)
{
try
{
hSession.save(object);
}
catch (HibernateException e)
{
hTransaction.rollback();
throw e;
}
}
public void update(C object)
{
try
{
hSession.update(object);
}
catch (HibernateException e)
{
hTransaction.rollback();
throw e;
}
}
public void delete(I id)
{
try
{
C actual = get(id);
hSession.delete(actual);
}
catch (HibernateException e)
{
hTransaction.rollback();
throw e;
}
}
}
Then extending above DAO in my DAO class like:
public class UserRoleDAO extends AbstractSimpleGenericDao<UserRole, UserRoleId> {
public List L() {
try {
String queryString = "from UserRole";
Query queryObject = hSession.createQuery(queryString);
return queryObject.list();
} catch (RuntimeException re) {
throw re;
}
}
Then in my struts Action class, instantiating DAO and retrieving list:
public class abc extends ActionSupport{
private UserRoleDAO userRoleDao = new UserRoleDAO();
private List ls=new ArrayList();
public String execute()
{
List ls=userRoleDao.L()
return "success";
}
}
If I am Calling this abc
Action class, by repetitive clicks on specified menu link then it causes Connection Leak, counts as opened connection that i am able to see using jProfiler, and is never going to close.
Meanwhile also, It's leaking connections.
StackTrace of all opened leaked connection's using jProfiler:
org.hibernate.transaction.JDBCTransaction.begin()
com.googlecode.s2hibernate.struts2.plugin.interceptors.SessionTransactionInjectorInter
ceptor.injectHibernateTransactionByAnnotation(java.lang.Object, org.hibernate.Session, boolean)
com.googlecode.s2hibernate.struts2.plugin.interceptors.SessionTransactionInjectorInter
ceptor.injectHibernateTransactionByAnnotation(java.lang.Object, org.hibernate.Session, boolean)
com.googlecode.s2hibernate.struts2.plugin.interceptors.SessionTransactionInjectorInter
ceptor.intercept(com.opensymphony.xwork2.ActionInvocation)
java.lang.Thread.run()
URL: /project/action-name
Why Hibernate is leaking these connections?
Is it like, Hibernate is keeping the connection in session and reusing the same connection and therefore, if at the same time if I am making concurrent request's, if session connection is occupied it would leak connections. This is just i am assuming. I don't have any idea.
In your hibernate configuration implicitly used DriverManagerConfigurationProvider
. This provider used by default unless you configured it with property connection.provider_class
.
This provider also implements a very rudimentary connection pool.
What it means "rudimentary connection pool". If you run your application you can see in the logs
[DriverManagerConnectionProvider] Using Hibernate built-in connection pool (not for production use!)
[DriverManagerConnectionProvider] Hibernate connection pool size: 20
You can also set this value via hibernate configuration property connection.pool_size
. But it doesn't limit you to the maximum opened connections count. You can open as many as you need connections while pool is empty. The provider will keep them open as it returns connections to pool on closeConnection
unless the current pool size not exceeds the value in the property connection.pool_size
. Once current pool size is not empty you cannot open any new connection because the connection provider returns connection from the pool.
As you can see now it's difficult to say that hibernate using this connection provider by default may leak the connections, I've just say it's impossible. However, it's not limited with the number of opened connections.
To make sure the connections are limited use a different connection provider. For example
you could use C3P0ConnectionProvider
and set the property hibernate.c3p0.max_size
to limit opened connections.