大型应用为了实现读写分离,便于数据的管理,提高系统的水平伸缩性,往往会用到多数据源。
1,数据源是对应不同数据库的,为了方便操作可以写一个数据库的配置文件
UPDATE_MYSQL.type=
mysql
UPDATE_MYSQL.autoCommitOnClose=
false
UPDATE_MYSQL.driverClassName=
com.mysql.jdbc.Driver
UPDATE_MYSQL.url=
jdbc:mysql://192.168.1.139:3306/testdatabase?useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true
UPDATE_MYSQL.username=
xccmysql
UPDATE_MYSQL.password=
xccW7W8
UPDATE_MYSQL.initialPoolSize=
5
SELECT_MYSQL.type=
mysql
SELECT_MYSQL.autoCommitOnClose=
false
SELECT_MYSQL.driverClassName=
com.mysql.jdbc.Driver
SELECT_MYSQL.url=
jdbc:mysql://192.168.1.139:3306/testmuti?useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true
SELECT_MYSQL.username=
root
SELECT_MYSQL.password=
xcc2009081231
SELECT_MYSQL.initialPoolSize=
5
2,然后再spring的配置文件里添加不同的数据源
<!-- 数据源的配置 -->
<
bean
id
=
"update_dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method
=
"close"
>
<
property
name
=
"driverClassName"
value
=
"${UPDATE_MYSQL.driverClassName}"
/>
<
property
name
=
"url"
value
=
"${UPDATE_MYSQL.url}"
/>
<
property
name
=
"username"
value
=
"${UPDATE_MYSQL.username}"
/>
<
property
name
=
"password"
value
=
"${UPDATE_MYSQL.password}"
/>
<!-- data source configuration -->
<
property
name
=
"initialSize"
value
=
"${UPDATE_MYSQL.initialPoolSize}"
/>
<!-- initial connections -->
<
property
name
=
"maxActive"
value
=
"10"
/>
<!-- MAX connections -->
<
property
name
=
"maxIdle"
value
=
"10"
/>
<!-- MAX idle connections -->
<
property
name
=
"minIdle"
value
=
"5"
/>
<!-- MIN idle connections -->
<!-- 处理mysql 8小时自动断开连接的问题 -->
<
property
name
=
"testWhileIdle"
value
=
"true"
/>
<
property
name
=
"testOnBorrow"
value
=
"false"
/>
<
property
name
=
"testOnReturn"
value
=
"false"
/>
<
property
name
=
"validationQuery"
value
=
"select 1"
/>
<
property
name
=
"timeBetweenEvictionRunsMillis"
value
=
"20000"
/>
<
property
name
=
"numTestsPerEvictionRun"
value
=
"100"
/>
</
bean
>
<
bean
id
=
"select_dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method
=
"close"
>
<
property
name
=
"driverClassName"
value
=
"${UPDATE_MYSQL.driverClassName}"
/>
<
property
name
=
"url"
value
=
"${SELECT_MYSQL.url}"
/>
<
property
name
=
"username"
value
=
"${SELECT_MYSQL.username}"
/>
<
property
name
=
"password"
value
=
"${SELECT_MYSQL.password}"
/>
<!-- data source configuration -->
<
property
name
=
"initialSize"
value
=
"${SELECT_MYSQL.initialPoolSize}"
/>
<!-- initial connections -->
<
property
name
=
"maxActive"
value
=
"10"
/>
<!-- MAX connections -->
<
property
name
=
"maxIdle"
value
=
"10"
/>
<!-- MAX idle connections -->
<
property
name
=
"minIdle"
value
=
"5"
/>
<!-- MIN idle connections -->
<!-- 处理mysql 8小时自动断开连接的问题 -->
<
property
name
=
"testWhileIdle"
value
=
"true"
/>
<
property
name
=
"testOnBorrow"
value
=
"false"
/>
<
property
name
=
"testOnReturn"
value
=
"false"
/>
<
property
name
=
"validationQuery"
value
=
"select 1"
/>
<
property
name
=
"timeBetweenEvictionRunsMillis"
value
=
"20000"
/>
<
property
name
=
"numTestsPerEvictionRun"
value
=
"100"
/>
</
bean
>
3,数据源准备好之后,基本工作,已完成,先放在一边,我们去java里面写数据源的名称常量类
package
org.iwall.muti.datasource;
/**
*
*
@author
Lee
*
*/
public
class
DataSourceNames {
public
static
final
String
UPDATE_MYSQL
=
"update_dataSource"
;
public
static
final
String
SELECT_MYSQL
=
"select_dataSource"
;
}
4,建立一个类,负责改变数据源的名称(其实可使用spring的注解切换不同的数据源)
package org.iwall.muti.datasource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 获得和设置上下文环境 主要负责改变上下文数据源的名称
* @author Lee
*
*/
public class DataSourceContextHolder {
private static final ThreadLocal contextHandler = new ThreadLocal(); // 线程本地环境
public static Log log = LogFactory.getLog(DataSourceContextHolder.class);
// 设置数据源类型
public static void setDataSourceType(String dataSourceType) {
log.info("set dataSource:" + dataSourceType);
contextHandler.set(dataSourceType);
}
// 获取数据源类型
public static String getDataSourceType() {
return (String) contextHandler.get();
}
// 清除数据源类型
public static void clearDataSourceType() {
contextHandler.remove();
}
}
5,建立动态数据源,主要实现 determineCurrentLookupKey这个方法
package org.iwall.muti.datasource;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
/**
*
* @author Lee
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource implements InitializingBean {
private Log log = LogFactory.getLog(DynamicDataSource.class);
/*
* 该方法必须要重写 方法是为了根据数据库标示符取得当前的数据库 既是获得数据源类型
*/
@Override
public Object determineCurrentLookupKey() {
log.info("starting determineCurrentLookupKey:" + DataSourceContextHolder.getDataSourceType());
return DataSourceContextHolder.getDataSourceType();
}
@Override
public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
log.info("starting setDataSourceLookup:" + DataSourceContextHolder.getDataSourceType());
super.setDataSourceLookup(dataSourceLookup);
}
@Override
public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
log.info("starting setDefaultTargetDataSource:" + DataSourceContextHolder.getDataSourceType());
super.setDefaultTargetDataSource(defaultTargetDataSource);
}
@Override
public void setTargetDataSources(Map targetDataSources) {
System.out.println("starting setTargetDataSources:" + DataSourceContextHolder.getDataSourceType());
super.setTargetDataSources(targetDataSources);
//重点
super.afterPropertiesSet();
}
}
6,数据源配置完了,java对应的类也写完了,就需要写映射关系了,其中key是对应java类里的数据源常量名,value是配置文件里的数据源名
<
bean
id
=
"dynamicDataSource"
class
=
"org.iwall.muti.datasource.DynamicDataSource"
>
<!-- 通过key-value的形式来关联数据源 -->
<
property
name
=
"targetDataSources"
>
<
map
key-type
=
"java.lang.String"
>
<
entry
key
=
"update_dataSource"
value-ref
=
"update_dataSource"
></
entry
>
<
entry
key
=
"select_dataSource"
value-ref
=
"select_dataSource"
></
entry
>
</
map
>
</
property
>
<
property
name
=
"defaultTargetDataSource"
ref
=
"update_dataSource"
>
</
property
>
</
bean
>
7,如果没有使用hibernate,mybatis等数据交互的框架,用spring的模板jdbc的话,注入一下就好
<
bean
id
=
"jdbcTemplate"
class
=
"org.springframework.jdbc.core.JdbcTemplate"
>
<
constructor-arg
ref
=
"dynamicDataSource"
/>
</
bean
>
8,总结下,这种方式,便于维护,基本只用修改数据库配置文件和spring配置文件即可。但是多个用户访问会争抢datasource,系统性能
会降低,(没测试过)。