简体   繁体   中英

Spring mutliple datasources with Hibernate gives: No Session found error

I am using Spring 4 with Hibernate 4 and trying to have multiple datasources configured. When I use the new second one, I always get an error.

    package org.miso.vre.config;

import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan("org.miso.vre")
@PropertySource("classpath:database.properties")
public class DatabaseConfig {

    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";

    private static final String PROPERTY_NAME_DATABASE_MISOFT_DRIVER = "db.misoft.driver";
    private static final String PROPERTY_NAME_DATABASE_MISOFT_PASSWORD = "db.misoft.password";
    private static final String PROPERTY_NAME_DATABASE_MISOFT_URL = "db.misoft.url";
    private static final String PROPERTY_NAME_DATABASE_MISOFT_USERNAME = "db.misoft.username";

    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";

    @Resource
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));

        return dataSource;
    }

    @Bean
    public DataSource dataSourceMISOFT() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_URL));
        dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_MISOFT_PASSWORD));

        return dataSource;
    }

    private Properties hibProperties() {
        Properties properties = new Properties();
        properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
        return properties;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource());
        sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        sessionFactoryBean.setHibernateProperties(hibProperties());
        return sessionFactoryBean;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactoryMISOFT() {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSourceMISOFT());
        sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        sessionFactoryBean.setHibernateProperties(hibProperties());
        return sessionFactoryBean;
    }
}

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.miso.vre.model.VRE_Record;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

@Repository
public class VRETestTableDAOImpl implements VRETestTableDAO {

    @Autowired
    @Qualifier(value="sessionFactoryMISOFT")
    private SessionFactory sessionFactoryMISOFT;

    private Session getCurrentSession() {
        return sessionFactoryMISOFT.getCurrentSession();
    }

    public VRE_Record getVRE_Record(int id) {
        VRE_Record vRE_Record = (VRE_Record) getCurrentSession().get(VRE_Record.class, id);
        return vRE_Record;
    }
}

>

package org.miso.vre.service;

import org.miso.vre.dao.VRETestTableDAO;
import org.miso.vre.model.VRE_Record;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created by PDuer on 12/29/2015.
 */
@Service
@Transactional
public class TestServiceImpl implements TestService {

    @Autowired
    private VRETestTableDAO vreTestTableDAO;

    @Override
    public VRE_Record getVRERecord (int id) {
        return vreTestTableDAO.getVRE_Record(id);
    }
}

exception org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: No Session found for current thread org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:943) org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822) javax.servlet.http.HttpServlet.service(HttpServlet.java:622) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807) javax.servlet.http.HttpServlet.service(HttpServlet.java:729) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) com.github.dandelion.datatables.core.web.filter.DatatablesFilter.doFilter(DatatablesFilter.java:73)

root cause org.hibernate.HibernateException: No Session found for current thread org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106) org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1013) org.miso.vre.dao.VRETestTableDAOImpl.getCurrentSession(VRETestTableDAOImpl.java:18) org.miso.vre.dao.VRETestTableDAOImpl.getVRE_Record(VRETestTableDAOImpl.java:22) org.miso.vre.service.TestServiceImpl.getVRERecord(TestServiceImpl.java:22) sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

The reason being, the sessionFactoryMISOFT is not associated with any transaction manager. Only the sessionFactory is associated with a transaction manager through transactionManager() method.

You need to create a similar method, say, transactionManagerMISOFT() and associate sessionFactoryMISOFT with this new transactionManager.

And when using the @Transaction attribute we need to specify which transactionManager needs to be used.

In my case, I have defined two sessionFactories and two transactionManager methods as below:

@Bean
public HibernateTransactionManager transactionManagerABC() {
    return new HibernateTransactionManager(sessionFactoryABC().getObject());
}

@Bean
public HibernateTransactionManager transactionManagerXYZ() {
    return new HibernateTransactionManager(sessionFactoryXYZ().getObject());
}   

And while using it I specify either transactionManagerABC or transactionManagerXYZ along with Transactional attribute in you service classes, as below:

@Transactional(transactionManager="transactionManagerABC")
public Forest getForestById(int id) {
    return forestDAO.getForestById(id);
}

You need to use Qualifier with Autowired annotation for sessionFactory, which I believe you already have:

@Qualifier("sessionFactoryABC")
private SessionFactory sessionFactory;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM