簡體   English   中英

Spring 4.3 -> 5.3 和 Hibernate 3.6 -> 5.4 升級導致錯誤:無法獲取當前線程的事務同步 Session

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM