Hi all,
We are running a web application to manage the user's own publications. The most important function of the application is the search. The user starts typing and if he's finished a query will be executed. The data is stored in a PostgreSQL database version 8.4. We are using the following frameworks:
hibernate 4.1.7.final with hibernate-entitymanager-4.1.7.final
hibernate-search-4.1.1.final
spring 3.1.1.release for dependency injection and transaction managment
OpenEntityManagerInViewFilter
Vaadin for GUI
The problem now is that we're running out of jdbc connections. Every time the user executes a search, three connections (we have three tabs with different search results) will be used and won't get released. After spending hours of debugging we detected that the EntityManagers from the main search method won't get closed. This makes sense because nowhere in the code these EntityManagers will be closed. If we close them on our own, we will get LazyInitializationExceptions when we try to show the search results because of the lazy loading of the dao's. So my questions are:
Do we have to create an EntityManager from the EntityManagerFactory every time a search has been executed? (The way it is already implemented, see bellow)
Or do we have to use the injected EntityManager? (As result we get LazyInitializationExceptions)
Why do we get LazyInitializationExceptions when we're using OpenEntityManagerInViewFilter?
In the class GenericJpaDaoImpl.java we provide the basic dao methods:
Code:
public class GenericJpaDaoImpl implements GenericDao, Serializable {
private static final long serialVersionUID = -1066085513967422846L;
private EntityManager entityManager;
@Transactional
public <T> void persist(T entity) {
entityManager.persist(entity);
}
@Transactional
public <T> T merge(T entity) {
return entityManager.merge(entity);
}
@Transactional
public <T> void remove(T entity) {
if (!entityManager.contains(entity)) {
entity = entityManager.merge(entity);
}
entityManager.remove(entity);
}
@Transactional
public <T> void removeAll(Class<T> entityClass) {
List<T> all = findAll(entityClass);
for (T entity : all) {
remove(entity);
}
}
public <T> List<T> findAll(Class<T> entityClass) {
CriteriaQuery<T> query = entityManager.getCriteriaBuilder()
.createQuery(entityClass);
query.from(entityClass);
List<T> results = entityManager.createQuery(query).getResultList();
return results;
}
public <T> T findById(Class<T> entityClass, Integer id) {
T result = entityManager.find(entityClass, id);
entityManager.refresh(result);
return result;
}
@SuppressWarnings("rawtypes")
public List findByNativeQuery(String sqlString,
Map<String, ?> params, int maxResults) {
Query query = entityManager.createNativeQuery(sqlString);
query.setMaxResults(maxResults);
return parametrizeQuery(params, query);
}
public <T> List<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
String queryName, Map<String, ?> params) {
Query query = entityManager.createNamedQuery(queryName, entityClass);
return parametrizeQuery(params, query);
}
public <T> List<T> findByNamedParam(Class<T> entityClass,
String queryString, Map<String, ?> params) {
Query query = entityManager.createQuery(queryString, entityClass);
return parametrizeQuery(params, query);
}
@Override
public <T> List<T> findByNamedParam(Class<T> entityClass,
String queryString, Map<String, ?> params, int firstResult,
int maxResults) {
Query query = entityManager.createQuery(queryString, entityClass);
query.setFirstResult(firstResult);
query.setMaxResults(maxResults);
return parametrizeQuery(params, query);
}
public EntityManager getEntityManager() {
return entityManager;
}
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
The class SearchServiceImpl.java executes the query from the user. The method query creates a new EntityManager every time a search will be executed. These EntityManagers won't get closed and as a result we're running out of connections. If we close them before the method returns, we get some LazyInitializationExceptions when we try to show the search result.
Code:
public class SearchServiceImpl {
private static final Log log = LogFactory.getLog(SearchServiceImpl.class);
private GenericDao dao;
private EntityManagerFactory emf;
public <T> QueryResult<T> query(Class<T> type,
Query query, String sortField, boolean reverseSort, int pageSize, int startRow) {
QueryResult<T> result = new QueryResult<T>();
try {
FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search
.getFullTextEntityManager(emf.createEntityManager());
FullTextQuery persistenceQuery = fullTextEntityManager
.createFullTextQuery(query, type);
if (!StringUtils.isEmpty(sortField)) {
Sort sort = new Sort(new SortField(
sortField, SortField.STRING,
!reverseSort));
persistenceQuery.setSort(sort);
}
if (pageSize > 0) {
persistenceQuery.setMaxResults(pageSize);
persistenceQuery.setFirstResult(startRow);
}
result.setResults(persistenceQuery.getResultList());
result.setTotalResultCount(persistenceQuery.getResultSize());
} catch (Exception e) {
log.error("Exception occured during executing the query", e);
}
return result;
}
public void setDao(GenericDao dao) {
this.dao = dao;
}
public void setEmf(EntityManagerFactory emf) {
this.emf = emf;
}
}
Additional information:
persistence.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="biblio" transaction-type="RESOURCE_LOCAL">
<class>...</class>
//Some classes
<properties>
<property name="hibernate.search.default.directory_provider" value="org.hibernate.search.store.impl.FSDirectoryProvider" />
<property name="hibernate.search.default.worker.thread_pool.size" value="5 " />
<property name="hibernate.search.default.worker.buffer_queue.max" value="30" />
<property name="hibernate.connection.release_mode" value="after_transaction" />
<property name="hibernate.ejb.discard_pc_on_close" value="true"/>
<property name="hibernate.show_sql" value = "false" />
</properties>
</persistence-unit>
</persistence>
applicationContext.xml
Code:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<!-- some service stuff -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<!-- ==================================== Transaction Manager ==================================-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="${persistence.path}" />
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false"/>
<property name="databasePlatform" value="org.hibernate.dialect.PostgreSQL82Dialect"/>
</bean>
</property>
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaProperties">
<props>
<prop key="hibernate.search.default.indexBase">${hibernate.search.default.indexBase}</prop>
<prop key="hibernate.search.default.exclusive_index_use">false</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<!-- ==================================== Transaction Manager ==================================
-->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
I'm really appreciate for every kind of help. If you need more information please let me know.