当前位置: 代码迷 >> Java Web开发 >> Spring动态添加使用数据源解决方案
  详细解决方案

Spring动态添加使用数据源解决方案

热度:82   发布时间:2016-04-16 22:04:29.0
Spring动态添加使用数据源
单位项目有个需求,我描述一下,希望会的人 ,帮忙指导一下
公司注册时,系统给该公司创建一个数据库,同时使用该数据库创建数据源,动态加载到内存.
公司用户登录时,根据登陆信息,判断该公司对应的数据源,切换到使用对应的数据源.该登录的用户操作过程中产生的业务数据都保存在对应的数据库中.
下边是我的实现思路,参考http://www.iteye.com/topic/72486
1.相关的配置文件



2.用户注册时,产生一个spring配置文件,该文件就是一个数据源的配置信息,如图:

配置文件产生后,新建一个数据,最后将该配置文件加载到内存中,代码如图:

3.编写一个获得和设置上下文环境的类,主要负责改变上下文数据源的名称

4.编写一个动态数据源类
public class DynamicDataSource extends AbstractRoutingDataSource {

/* 
 * 该方法必须要重写  方法是为了根据数据库标示符取得当前的数据库
 */
@Override
public Object determineCurrentLookupKey() {
DataSourceType dataSourceType= DataSourceContextHolder.getDataSourceType();
return dataSourceType;
}

@Override
public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
super.setDataSourceLookup(dataSourceLookup);
}

@Override
public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
}

@Override
public void setTargetDataSources(Map targetDataSources) {
super.setTargetDataSources(targetDataSources);
}

}

5.最后开始简单的测试
@Test
public void test() {
try {
List<UserinfoEntity> list = userInfoService.getList(UserinfoEntity.class);
System.out.println(list.size());

String dataSourceName = "qqq";
String url = "jdbc:mysql://127.0.0.1:3306/mos_saas_test";
String username = "root";
String password = "root";
ConfigFileCreator.createConfigFile(dataSourceName, url, username, password);
DynamicLoadBean dynamicBeanLoad =(DynamicLoadBean)SpringContextUtil.getBean("dynamicLoadBean");   
dynamicBeanLoad.loadBean("classpath:mos/qqq.xml"); 
// dynamicBeanLoad.registBean(dataSourceName, "parentDataSource");
DruidDataSource dds = (DruidDataSource) SpringContextUtil.getBean(dataSourceName);
DynamicDataSource ds = (DynamicDataSource)SpringContextUtil.getBean("dataSource");
// Map targetDataSources = new HashMap();
// targetDataSources.put(DataSourceType.qqq, dds);
//
// ds.setTargetDataSources(targetDataSources);
// DataSourceLookup dataSourceLookup = new MapDataSourceLookup();
// dataSourceLookup.getDataSource("qqq");
//
// ds.setDataSourceLookup(dataSourceLookup);

DataSourceContextHolder.setDataSourceType(DataSourceType.qqq);

List<UserinfoEntity> list2 = userInfoService.getList(UserinfoEntity.class);
System.out.println(list2.size());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

结果是数据源确实改变了,但是对数据库的操作还是基于默认数据源的,不知道怎么回事,求技术大牛给予帮助
------解决方案--------------------
你的sessionfactory 还是最开始那个。
你新加的spring配置文件只配置了一个数据源,sessionFactory没变。

你需要创建不同的sessionFactory。
根据数据源来创建。

------解决方案--------------------
sessionFactory没有改变,需要在生成一个sessionFactory,多数据源还要考虑事物的问题,tomcat对多数据源事物支持不是太好
------解决方案--------------------
又看到一个在spring里使用ThreadLocal作为路由数据源实现方式的案例。
这种实现在普通情况下确实能通过取当前线程实现数据源的定位,但是如果应用存在使用spring事务的情况,这么做就是在挖地雷。
因为spring推荐的scope prototype模式下bean都是单例,并发的时候依靠spring内部的ThreadLocal切换各个线程的参数,而spring的事务机制会针对每一个事务新开一个线程,最后导致在有事务的情况下,spring内部的事务线程和自定义路由使用的数据源定位线程不一致,数据源定位失败。
表现出来的现象就是,一个有spring事务的servcie里,无法调用两个数据源,无论怎么配置都会导致数据源被路由到同一个线程。
  相关解决方案