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
  • 11
  • 1
  • which version of spring are you trying here ...While I get the same exception when I use spring 5.3.4 but not in spring 5.1.12 Release. – ragul rangarajan Mar 18 '21 at 08:32
  • I was migrating spring 3.2 to 5.1.x. Luckily, I got a solution for the problem and I am going to post the solution in a separate comment. – mambo Mar 19 '21 at 16:12
  • Great ..that u got the solution. Share ur solution here so it will be helpful for all. – ragul rangarajan Mar 22 '21 at 08:08

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
  • 125
  • 2
  • 10
  • 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