1

I am working on migrating an application from Spring 3.2 to Spring 5. The application uses AWS RDS with a primary database as primary or master datasource and a replica database as read-only datasource. The application creates one session factory ( primarySessionFacotry) instance for the primary data source and another one ( readOnlySessionFactory) for the read-only data source so that the same DAO can be used for both datasource by wiring each session factories.

appContext-hibernate.xml

<bean id="primaryDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass">
        <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="jdbcUrl">
        <value>${database.jdbcurl}</value>
    </property>
    <property name="user">
        <value>${database.dbuser}</value>
    </property>
    <property name="password">
        <value>${database.dbpassword}</value>
    </property>

</bean>

<bean id="primarySessionFactory"
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="primaryDataSource"/>
    <property name="mappingResources" ref="hbmFileLocations">
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">${hibernate.showSQL}</prop>
            <prop key="hibernate.format_sql">${hibernate.formatSQL}</prop>
        </props>
    </property>
</bean>

<util:list id="hbmFileLocations" value-type="java.lang.String">
    <value>com/xxxx/yyyyy/persistence/mappings/users.hbm.xml</value>
</util:list>

<bean id="primaryTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="primarySessionFactory">
    </property>
</bean>

<tx:annotation-driven transaction-manager="primaryTransactionManager"/>

appContext-hibernate-ro.xml

<bean id="readOnlyDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass">
        <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="jdbcUrl">
        <value>${database.readonly.jdbcurl}</value>
    </property>
    <property name="user">
        <value>${database.readonly.dbuser}</value>
    </property>
    <property name="password">
        <value>${database.readonly.dbpassword}</value>
    </property>
    
</bean>

<bean id="readOnlySessionFactory"
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="readOnlyDataSource"/>
    <property name="mappingResources" ref="hbmFileLocations">
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">${hibernate.readonly.showSQL}</prop>
            <prop key="hibernate.format_sql">${hibernate.readonly.formatSQL}</prop>
        </props>
    </property>

</bean>

<bean id="readOnlyTransactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="readOnlySessionFactory"/>
</bean>

<tx:annotation-driven transaction-manager="readOnlyTransactionManager"/>

DAOs are instantiated like this

<bean id="userDao" class="xxxxx.persistence.UserDao">
    <property name="sessionFactory" ref="primarySessionFactory"/>
</bean>
<bean id="readOnlyUserDao" class="xxxxx.persistence.UserDao">
    <property name="sessionFactory" ref="readOnlySessionFactory"/>
</bean>

This UserDao has a method like below

@Transactional
public List<User> getItems()
{
    return sessionFactory.getCurrentSession().createQuery("from User user where isDeleted=false").list();
}

We are getting below exception when using the UserDao.getItems() method with readOnlyUserDao intance.

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:143)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:497)

Please note that the same code is perfectly working with Spring ( spring-orm and spring-tx 3.2)

Please assist to resolve this.

mambo
  • 9
  • 1
  • 2

1 Answers1

0

I had the same issue and followed the step mentioned here and which works fine for my case. Spring Hibernate - Could not obtain transaction-synchronized Session for current thread

Session session;
try {
    session = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
    session = sessionFactory.openSession();
}
return session;
ragul rangarajan
  • 167
  • 2
  • 12
  • Thanks for your answer Ragul Rangarajan. This would need code change for each and every method we have which is in thousands. I figured out another solution for my problem and will post it in a separate comment. – mambo Mar 19 '21 at 16:14
  • It looks good at the beginning but causes my application fails entirely after one hour. Still cannot understand why. Reverting back, it throws the exception but at least the application does not fail entirely due to database problem. – mercury May 04 '22 at 01:07
  • 1
    @ragul rangarajan: That is not a solution. When the motor of your car is damaged, the requested solution would be to repair to motor. What you are doing here is taking another car. Because sessionFactory.getCurrentSession() is supposed to manage the session. But you suggest to open a new one and manage it yourself. – d00d Sep 02 '22 at 07:46
  • @mambo did you manage to post your own solution? – maxxyme May 05 '23 at 14:22