Spring + Hibernate:如何动态处理Multiply(无限)数据源和会话工厂?

时间:2014-10-09 00:36:58

标签: spring hibernate sessionfactory

我们的应用程序可能有多个数据库。对于同一应用程序实例,数据库可以是不同类型(Oracle和MS SQL)。数据库结构略有不同,但使用了相同的Hibernate POJO集。列表od数据库只能在应用程序实际启动时确定(因此不能存储为固定的XML)

用户需要在登录过程中选择数据库。所选的数据库存储在HTTP会话中。

所以我想使用Sping自动布线将会话工厂自动连接到Web控制器中的DAO取决于当前用户。像:

@Repository
@Transactional
@Controller
public abstract class UserGroupDAO {

    @Autowired
    @Qualifier("sessionFactory")
    private SessionFactory sessionFactory;

    public List<Users> getListOfUsers() {
        Session session = sessionFactory.currentSession();
        return session.createCriteria(Users.class).list();
    }
}


@Controller
public class WebController {

    @Autowired
    @Qualifier("userGroupDAO")
    private UserGroupDAO userGroupDAO;  

    @RequestMapping("/greeting.html")
    public ModelAndView greeting(Model model) {
        userGroupDAO.getListOfUsers();
    }

例如:有2个DB - Oracle_DB和MS_SQL_DB以及两个用户A和B.用户A登录Oracle_DB,用户B登录MS_SQL_DB。当用户A遇到/问候时,他应该看到来自Oracle_DB的用户列表,当用户B遇到/问候时 - 来自MS_SQL_DB。

我查看了AbstractRoutingDatasource,但它看起来只适用于具有多个数据源的单个会话工厂。但是,我正在为每个数据源(以及事务管理器)寻找单独的会话工厂。

提前感谢您的帮助

问题摘要

数据库是动态生成的,因此无法将数据库设置硬编码到配置文件中。 Spring应用程序需要能够确定哪些数据库可用,然后连接到它们。

1 个答案:

答案 0 :(得分:0)

解决方案是 1)将UserGroupDAO,SessionFactory等范围设置为&#39; session&#39;

@Repository
@Transactional
@Scope(value="session",proxyMode=ScopedProxyMode.TARGET_CLASS) 
public class UserGroupDAO extends GeneralDAO {

2)在Singleton(DataSourceProvider)中手动初始化SessionFactory,Session等,并从ApplicationContextConfig中的Singleton中获取它

@Configuration
@ComponentScan(....)
@EnableTransactionManagement
public class ApplicationContextConfig {
    @Autowired
    @Bean("sessionFactory")
    @Scope(value="session")
    public SessionFactory getSessionFactory(DataSource dataSource) {
    return DataSourceProvider.getInstance().getDatasourceByContext().getSessionFactory();
    }
    @Autowired
    @Bean("dataSource")
    @Scope(value="session")
    public DataSource getDataSource() {
        return DataSourceProvider.getInstance().getDatasourceByContext().getDataSource();
    }

3)检测DataSourceProvider中的当前数据库

public class DataSourceProvider {

private static DataSourceProvider instance = new DataSourceProvider();

public static DataSourceProvider getInstance() {
    return instance;
}

private HashMap<String, MyDataSource> dataSources;

private DataSourceProvider(){
}

public MyDataSource getDatasourceByContext() {
    String connectionName;
    if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        if (request==null) {
            connectionName = null;
        } else {
            //"currentDatabase" is set during logon
            connectionName = (String)request.getSession().getAttribute("currentDatabase");
        }
    } else {
        connectionName = null;
    }
    if (connectionName!=null) {
        MyDataSource dataSource = dataSources.get(connectionName);
        if (dataSource != null) {
            return dataSource;
        }
    }
    throw new IllegalStateException("No datasource for the context");
}