聊聊Java项⽬的动态多数据源配置
在我们的项⽬中遇到这样⼀个问题:我们的项⽬需要连接多个数据库,⽽且不同的客户在每次访问中根据需要会去访问不同的数据库。所以就采⽤了多数据源的⽅式(可以根据客户的需求去连接客户所需要的真正的数据源,即提供动态切换数据源的功能)。
多数据源配置是怎么个配置法,其中⽤到了些什么技术,想必⼤家都会有这个疑问,下⾯将逐⼀介绍。
⼤概思路是这样的:在登录页⾯放置⼀个下拉选择列表(使⽤的Bootstrap框架的dropdown-menu,不懂的可以百度⼀下特别好⽤),下拉列表在加载以前是从后台读取的⼀个包含了多个数据库信息的Json⽂件,前台通过js循环渲染出来。另外有⼀个⼦页⾯可以创建新的数据库保存到刚才的那个Json⽂件中。
关键点来了,最主要的是登录的时候选了不同的数据库,后台是怎么知道并且登录成功的。
写⼀个DBContextHolder类放⼀个多线程的变量记录当前数据源,具体实现类继承AbstractRoutingDataSource类并且重写⽅法determineCurrentLookupKey获取当前数据源,如果当前数据源不存在就新建并且要通知spring容器。
具体代码如下:
l配置⽂件内容:
<bean id="datasource"  class="xxxxxxxxxxx.DynamicDataSource">
<property name="targetDataSources">  <map></map>  </property>
</bean>
2.DynamicDataSource.class
package    ;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public  class  DynamicDataSource    extends    AbstractRoutingDataSource{
/*l配置⽂件中配置数据源为此类*/
public DynamicDataSource(){                                                    /*默认数据源*/
HashMapmap_1 = new HashMap();
map_1.put("DRIVER_CLASS", "sql.jdbc.Driver");
map_1.put("dbUrl", "jdbc:mysql://127.0.0.1:3306/ifms?
useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&autoReconnect=true");
map_1.put("dbUserName", "root");
map_1.put("dbPassword", "123456");
dbMap.put("db0", map_1);
}
@Override
protected  Object determineCurrentLookupKey() {          /*得到当前数据源*/
return  CustomerType();
}
public void setTargetDataSources(MaptargetDataSources) {
this._targetDataSources = targetDataSources;
super.setTargetDataSources(this._targetDataSources);
super.afterPropertiesSet();//当我们添加数据库,切换了数据源,要通知当前spring容器  }
public void addTargetDataSource(String key, BasicDataSource dataSource) {
this._targetDataSources.put(key, dataSource);
this.setTargetDataSources(this._targetDataSources);
}
public BasicDataSource createDataSource(String driverClassName, String url,
String username, String password) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setTestWhileIdle(true);
return dataSource;
}
/**
* @param serverId
* @describe 数据源存在时不做处理,不存在时创建新的数据源链接,并将新数据链接添加⾄缓存*/
public void selectDataSource(String serverId) {
Object sid = CustomerType();
Object obj = this._(serverId);
if (obj != null && sid.equals(serverId + "")) {
return;
} else {
System.out.println("---数据源不存在,创建数据源");
BasicDataSource dataSource = DataSource(serverId);  //判断当前数据源是否存在
if (null != dataSource)
this.setDataSource(serverId, dataSource);                        //设置当前数据源
}
}
public void setDataSource(String serverId, BasicDataSource dataSource) {
this.addTargetDataSource(serverId, dataSource);
DBContextHolder.setCustomerType(serverId);
}
}
3.DBContextHolder.class
package  ;
public  class  DBContextHolder{
private  static  final  Thread  Local contextHolder =newThreadLocal();
public  static  void  setCustomerType(String customerType) {
contextHolder.set(customerType);
}
public  static  String getCustomerType() {
return  ();
}
bootstrap项目
public  static  void  clearCustomerType() {
}
}
其中遇到个问题,如果将数据源变量定义为多线程的时候,如果前台页⾯另起⼀个线程并且中途出现异常之后会获取不到当前数据源。所以暂时改为了⼀个静态变量但是只能⽀持单线程。如果有⼀台电脑正⽤着A数据库,另外⼀台电脑突然⽤B数据库登录,那原来那个的数据库也会变成A。⽬前还没有到好的⽅法解决这个问题,到了会继续更新。如果谁有⽐较好的⽅法也可以告诉我,灰常感

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。