[英]Spring and Hibernate - Could not obtain transaction-synchronized Session for current thread
[英]Spring 4.3 -> 5.3 and Hibernate 3.6 -> 5.4 upgrade results in error: Could not obtain transaction-synchronized Session for current thread
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. 更新 Spring 后,我收到標題中所述的錯誤。 這是我的代碼:
我有自己的 sessionFactory 實現和這個導入
import org.springframework.orm.hibernate3.LocalSessionFactoryBuilder;
我改成
import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
這是我的會話工廠
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;
}
}
對於 Spring 4.x 到 5.x 和 Hibernate 3.x 到 5.x 的更新,當我將導入從 v3 更改為 v5 時,我不得不將參數sfb
添加到buildSessionFactory
方法中,因為此方法的簽名具有改變了。 在那之后,我開始從標題中得到錯誤。
在 Spring 的 SpringSessionContext#currentSession() 方法中拋出錯誤。 給定的 if 子句都不是真的,這就是為什么在方法結束時會拋出此異常。
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
這是 sessionFactoryBean。 如您所見,我還嘗試取消注釋自定義 sessionFactory 並改用開箱即用的解決方案,但這會導致相同的錯誤。
<!-- Hibernate SessionFactory Definition -->
<!-- <bean id="sessionFactory" class="com.myApp.common.integration.orm.MySessionFactory">-->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<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>
再深入一點:我有一個擴展 class CommonDaoHibernateImpl.java
這是我使用的每個 DAO 的擴展。 在這個 class 中,我有這樣的方法:
@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();
... }
錯誤發生在第一行,所以我試圖改變它:
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();
}
... }
這給了我一個不同的錯誤,這是一件好事,但仍然是一個錯誤:
Caused by: java.sql.SQLException: javax.resource.ResourceException: IJ000453: Unable to get managed connection for java:/MyConnection
at org.jboss.ironjacamar.jdbcadapters@1.4.27.Final//org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:159)
at org.jboss.as.connector@23.0.2.Final//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 org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.AbstractConnectionManager.getManagedConnection(AbstractConnectionManager.java:690)
at org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.tx.TxConnectionManagerImpl.getManagedConnection(TxConnectionManagerImpl.java:440)
at org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:789)
at org.jboss.ironjacamar.jdbcadapters@1.4.27.Final//org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:151)
... 107 more
Caused by: javax.resource.ResourceException: IJ031084: Unable to create connection
at org.jboss.ironjacamar.jdbcadapters@1.4.27.Final//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createLocalManagedConnection(LocalManagedConnectionFactory.java:345)
at org.jboss.ironjacamar.jdbcadapters@1.4.27.Final//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.getLocalManagedConnection(LocalManagedConnectionFactory.java:352)
at org.jboss.ironjacamar.jdbcadapters@1.4.27.Final//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createManagedConnection(LocalManagedConnectionFactory.java:287)
at org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreConcurrentLinkedDequeManagedConnectionPool.createConnectionEventListener(SemaphoreConcurrentLinkedDequeManagedConnectionPool.java:1322)
at org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreConcurrentLinkedDequeManagedConnectionPool.getConnection(SemaphoreConcurrentLinkedDequeManagedConnectionPool.java:499)
at org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.pool.AbstractPool.getSimpleConnection(AbstractPool.java:632)
at org.jboss.ironjacamar.impl@1.4.27.Final//org.jboss.jca.core.connectionmanager.pool.AbstractPool.getConnection(AbstractPool.java:604)
at org.jboss.ironjacamar.impl@1.4.27.Final//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 org.postgresql@42.2.20//org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:613)
at org.postgresql@42.2.20//org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:161)
at org.postgresql@42.2.20//org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213)
at org.postgresql@42.2.20//org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51)
at org.postgresql@42.2.20//org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:223)
at org.postgresql@42.2.20//org.postgresql.Driver.makeConnection(Driver.java:465)
at org.postgresql@42.2.20//org.postgresql.Driver.connect(Driver.java:264)
at org.jboss.ironjacamar.jdbcadapters@1.4.27.Final//org.jboss.jca.adapters.jdbc.local.LocalManagedConnectionFactory.createLocalManagedConnection(LocalManagedConnectionFactory.java:321)
... 117 more
這表明系統在應用程序啟動期間創建了大量會話(?),直到達到閾值。
我想我已經找到了解決我的問題的方法。 我有一個抽象的 class CommonHibernateDAOImpl.java
由我擁有的每個 DAO 擴展並實現每個 DAO 使用的一些方法,例如
@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();
}
雖然這種方法在 Hibernate 3.6 中運行得非常好,但它在 5.4 中停止工作並導致錯誤:
Caused by: org.hibernate.HibernateException: Calling method 'createCriteria' is not valid without an active transaction (Current status: NOT_ACTIVE)
為了解決這個問題,我使用@Autowire DI'ed sessionFactory 並重寫了會話的創建方式,並關閉了 session,根據文檔,在使用.getCurrentSessioon()
而不是.openSession()
時不需要這樣做。 但只是為了確保這不再導致“連接過多”的問題。
@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;
}
不管出於什么奇怪的原因,只要我之前手動創建了一個事務,它就可以工作,而 Hibernate 3.6 沒有這樣做。 而且我絕對確定這不是應該的方式,因為我有代碼,它使用 Spring 內部的getHibernateTemplate().findAll()
function:
@Override
public final List<ENTITY> findAll(final Class<ENTITY> entityClass) {
return getHibernateTemplate().loadAll(entityClass);
}
這不會為我創建新事務,並且出現相同的錯誤:
@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();
}));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.