I am currently upgrading a project from Hibernate 3 to Hibernate 5 and from Java 7 to Java 17. We also use Spring 4.3.x which I updated to the 5.3 stream. After updating Spring, I get the error stated in the headline. Here's my code:
I have my own implementation of the sessionFactory with this import
import org.springframework.orm.hibernate3.LocalSessionFactoryBuilder;
that i changed to
import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
Here's my SessionFactory
public class MySessionFactory extends LocalSessionFactoryBean {
/** The Constant defaultLocationPattern. */
private final static String defaultLocationPattern = "classpath*:/com/*/*/**/integration/hbm/*.hbm.xml";
/** The Constant log. */
private static final Log log = LogFactory.getLog(MySessionFactory.class);
/** The location pattern. */
private String locationPattern;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Collect hbm resources.
*/
private void collectHbmResources() {
try {
final ClassLoader cl = this.getClass().getClassLoader();
final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl);
final Resource[] items = resolver.getResources(locationPattern != null ? locationPattern:defaultLocationPattern);
log.info("Found " items.length " resources");
for (Resource resource:items) {
log.info("........................................................" resource.getFilename());
}
setMappingLocations(items);
} catch (Exception e) {
log.error(e);
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
@Override
protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
collectHbmResources();
return super.buildSessionFactory(sfb);
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------
/**
* Sets the location pattern.
*
* @param locationPattern the new location pattern
*/
public void setLocationPattern(final String locationPattern) {
this.locationPattern = locationPattern;
}
}
For the update of Spring 4.x to 5.x and Hibernate 3.x to 5.x and when I changed the import from v3 to v5, I had to add the parameter sfb
to the buildSessionFactory
method because the signature of this method had changed. After that, I started to get the error from the headline.
The error is thrown in Spring's SpringSessionContext#currentSession() method. None of the given if-clauses turn out to be true which is why at the end of the method, this exception is thrown.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'txtTextItemsCacheService' defined in class path resource [com/cl/myApp/core/txt/service/spring-txt-service-beans.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1804)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at deployment.myApp.war//org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at deployment.myApp.war//org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
... 80 more
Caused by: org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at deployment.myApp.war//org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:142)
at deployment.myApp.war//org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:491)
at deployment.myApp.war//com.pal.myApp.common.integration.dao.impl.CommonHibernateDAOImpl.findByCriteria(CommonHibernateDAOImpl.java:521)
at deployment.myApp.war//com.pal.myApp.common.service.impl.CommonCrudServiceImpl.findByCriteria(CommonCrudServiceImpl.java:46)
at deployment.myApp.war//com.pal.myApp.common.service.impl.CommonCrudServiceImpl.findByCriteria(CommonCrudServiceImpl.java:30)
at deployment.myApp.war//com.cl.myApp.core.pm.service.impl.PmPropertyServiceImpl.findByKey(PmPropertyServiceImpl.java:67)
at deployment.myApp.war//com.cl.myApp.core.pm.service.impl.PmPropertyServiceImpl.findValueByKey(PmPropertyServiceImpl.java:109)
at deployment.myApp.war//com.cl.myApp.core.pm.service.impl.PmPropertyValueServiceImpl.getPropertyValue(PmPropertyValueServiceImpl.java:105)
at deployment.myApp.war//com.cl.myApp.core.pm.service.impl.PmPropertyValueServiceImpl.getStringProperty(PmPropertyValueServiceImpl.java:26)
at deployment.myApp.war//com.cl.myApp.core.txt.service.TxtTextItemsCacheServiceImpl.init(TxtTextItemsCacheServiceImpl.java:52)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1930)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1872)
at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
... 87 more
Here's the sessionFactoryBean. As you can see, I also tried to uncomment the custom sessionFactory and use the out of the box solution instead, but that results in the same error.
<!-- Hibernate SessionFactory Definition -->
<!-- <bean id="sessionFactory" >-->
<bean id="sessionFactory" >
<property name="mappingLocations" value="classpath*:/com/*/*/**/integration/hbm/*.hbm.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">${hibernate.cglib.use_reflection_optimizer}</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider_class}</prop>
<prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
<prop key="hibernate.connection.release_mode">${hibernate.connection.release_mode}</prop>
<prop key="hibernate.c3p0.min_size">${hibernate.c3p0.min_size}</prop>
<prop key="hibernate.c3p0.max_size">${hibernate.c3p0.max_size}</prop>
<prop key="hibernate.c3p0.timeout">${hibernate.c3p0.timeout}</prop>
<prop key="hibernate.c3p0.max_statements">${hibernate.c3p0.max_statements}</prop>
<prop key="hibernate.c3p0.idle_test_period">${hibernate.c3p0.idle_test_period}</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"/>
</bean>
And to dig a little deeper: I have an extension class CommonDaoHibernateImpl.java
which is an extension to every DAO i use. In this class, I have methods like this:
@Override
@SuppressWarnings({ "unchecked", "deprecation" })
public List<ENTITY> findByCriteria(final Map<String, Object> criteriaMap, final List<String> fields, final Class<ENTITY> entityClass) {
final Criteria criteria = this.getSessionFactory().getCurrentSession().createCriteria(entityClass);
final Set<String> keys = criteriaMap.keySet();
... }
The error occurs in the first line, so I tried to change it like that:
public List<ENTITY> findByCriteria(final Map<String, Object> criteriaMap, final List<String> fields, final Class<ENTITY> entityClass) {
Session session;
try {
session = this.getSessionFactory().getCurrentSession();
} catch (HibernateException e) {
session = this.getSessionFactory().openSession();
}
... }
Which gives me a different error, which is a good thing but still an error:
Caused by: java.sql.SQLException: javax.resource.ResourceException: IJ000453: Unable to get managed connection for java:/MyConnection
at [email protected]//org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:159)
at [email protected]//org.jboss.as.connector.subsystems.datasources.WildFlyDataSource.getConnection(WildFlyDataSource.java:64)
at deployment.myApp.war//org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)
at deployment.myApp.war//org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38)
at deployment.myApp.war//org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:108)
... 103 more
Caused by: javax.resource.ResourceException: IJ000453: Unable to get managed connection for java:/MyConnection
at [email protected]//org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:690)
at [email protected]//org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl.getManagedConnection(TxConnectionManagerImpl.java:440)
at [email protected]//org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:789)
at [email protected]//org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:151)
... 107 more
Caused by: javax.resource.ResourceException: IJ031084: Unable to create connection
at [email protected]//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createLocalManagedConnection(LocalManagedConnectionFactory.java:345)
at [email protected]//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.getLocalManagedConnection(LocalManagedConnectionFactory.java:352)
at [email protected]//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createManagedConnection(LocalManagedConnectionFactory.java:287)
at [email protected]//org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreConcurrentLinkedDequeManagedConnectionPool.createConnectionEventListener(SemaphoreConcurrentLinkedDequeManagedConnectionPool.java:1322)
at [email protected]//org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreConcurrentLinkedDequeManagedConnectionPool.getConnection(SemaphoreConcurrentLinkedDequeManagedConnectionPool.java:499)
at [email protected]//org.jboss.jca.core.connectionmanager.pool.AbstractPool.getSimpleConnection(AbstractPool.java:632)
at [email protected]//org.jboss.jca.core.connectionmanager.pool.AbstractPool.getConnection(AbstractPool.java:604)
at [email protected]//org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:624)
... 110 more
Caused by: org.postgresql.util.PSQLException: FATAL: sorry, too many clients already
at [email protected]//org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:613)
at [email protected]//org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:161)
at [email protected]//org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213)
at [email protected]//org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51)
at [email protected]//org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:223)
at [email protected]//org.postgresql.Driver.makeConnection(Driver.java:465)
at [email protected]//org.postgresql.Driver.connect(Driver.java:264)
at [email protected]//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createLocalManagedConnection(LocalManagedConnectionFactory.java:321)
... 117 more
It indicates that the system is creating a lot of sessions (?) during startup of the app until the threshold is reached.
CodePudding user response:
I think I have found a solution for my problem. I have an abstract class CommonHibernateDAOImpl.java
which is extended by every DAO that I have and implements some methods used by each DAO, such as
@Override
@SuppressWarnings({ "unchecked", "deprecation" })
public List<ENTITY> findByCriteria(final Map<String, Object> criteriaMap, final List<String> fields, final Class<ENTITY> entityClass) {
final Criteria criteria = sessionFactory.getCurrentSession().createCriteria(entityClass);
return criteria.list();
}
While this method the way it is would run perfectly fine in Hibernate 3.6, it stopped working in 5.4 and results in the error:
Caused by: org.hibernate.HibernateException: Calling method 'createCriteria' is not valid without an active transaction (Current status: NOT_ACTIVE)
To solve this, I DI'ed the sessionFactory with @Autowire and rewrote the way the sessions are being created and I closed the session, which according to the docs is not necessary when using .getCurrentSessioon()
instead of .openSession()
. But just to make sure that this is not causing the problems with the "too many connections" anymore.
@Autowire
private SessionFactory sessionFactory;
@Override
public List<ENTITY> findByCriteria(final Map<String, Object> criteriaMap, final List<String> fields, final Class<ENTITY> entityClass) {
Session session = sessionFactory.getCurrentSession();
final Criteria criteria;
List ret = null;
try {
Transaction tx = session.beginTransaction();
criteria = session.createCriteria(entityClass);
ret = criteria.list();
} catch (HibernateException e) {
} finally {
if (currentSession() != null) {
currentSession().close();
}
}
return ret;
}
And for whatever weird reason, it worked as soon as I manually created a transaction before, which was not done with Hibernate 3.6. And I am absolutely sure that this is not the way it should because I have code, that uses the Spring-internal getHibernateTemplate().findAll()
function:
@Override
public final List<ENTITY> findAll(final Class<ENTITY> entityClass) {
return getHibernateTemplate().loadAll(entityClass);
}
Which does not create a new transaction for me and there, the same error appears:
@Override
@SuppressWarnings({"unchecked", "deprecation"})
public <T> List<T> loadAll(Class<T> entityClass) throws DataAccessException {
return nonNull(executeWithNativeSession((HibernateCallback<List<T>>) session -> {
Criteria criteria = session.createCriteria(entityClass);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
prepareCriteria(criteria);
return criteria.list();
}));
}