mybatis目前只支持单数据源配置,如果想要切换数据源的话不能够灵活的操作,因此想要修改mybatis源码已支持数据源灵活切换,最终使用方式如下,指定对应的数据源,mybatis自动支持去指定的数据源下面的数据库下查询,同时也支持不同的数据库连接池。
private static void dbkeyTest() {
long start = System.currentTimeMillis();
final SqlSession session = sqlSessionFactory.openSession();
// 指定特定的dbkey数据源查询
Student student = session.selectOne("getStudent", 1, "db1");
if (null != student) {
System.out.println(student.toString());
}
final SqlSession session1 = sqlSessionFactory.openSession();
Student student1 = session1.selectOne("getStudent", 1, "db2");
if (null != student1) {
System.out.println(student1.toString());
}
long end = System.currentTimeMillis();
System.out.println("程序执行时间为" + (end - start));
}
mybatis配置文件通过如下的配置来支持多数据源
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="maintest.C3P0DataSourceFactory">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
dataSource>
<dataSources>
<dataSource type="POOLED" id="db1">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
<dataSource type="POOLED" id="db2">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test1?characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
dataSources>
environment>
environments>
结果:第一个数据源test数据库中没有这条数据没打印这条记录信息,第二个数据源test1数据库中有这条记录打印出这条数据,实现了动态灵活切换数据源的目标
------------dbkey is = db1
DEBUG [main] - Opening JDBC Connection, dbKey=db1
DEBUG [main] - Created connection 2006034581.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@7791a895]
DEBUG [main] - ==> Preparing: select * from student where id= ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 0
------------dbkey is = db2
DEBUG [main] - Opening JDBC Connection, dbKey=db2
DEBUG [main] - Created connection 1427810650.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@551aa95a]
DEBUG [main] - ==> Preparing: select * from student where id= ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
[id=1, studentID=2, name=aaa]
1、mybatis-3-config.dtd 文件修改增加dataSources元素信息,并对dataSources上层的environment元素进行修改
<!ELEMENT environment (transactionManager,dataSource,dataSources*)>
<!ATTLIST environment
id CDATA #REQUIRED
>
<!ELEMENT dataSources (dataSource+)>
<!ATTLIST dataSources
id CDATA #IMPLIED
>
2、解析环境配置的时候,增加解析dataSources的逻辑
Environment类中增加dataSourceMap属性,解析配置文件的时候将数据源id和对应的数据源加载到dataSourceMap中,Environment构建的时候用的是builder模式
private final Map<String, DataSource> dataSourceMap;
XMLConfigBuilder 解析的时候修改
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
// 创建dataSourceFactory工厂
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
// 增加解析datasource的逻辑
Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)
.dataSource(dataSource).dataSourceMap(dataSourceElementMap(child.evalNode("dataSources")));
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
/**
* 解析datasources节点
*
* @param context
* @return
* @throws Exception
*/
private Map<String, DataSource> dataSourceElementMap(XNode context) throws Exception {
if (context != null) {
Map<String, DataSource> dataSourceMap = new HashMap<String, DataSource>();
for (XNode child : context.getChildren()) {
DataSourceFactory dsFactory = dataSourceElement(child);
DataSource dataSource = dsFactory.getDataSource();
String id = child.getStringAttribute("id");
dataSourceMap.put(id, dataSource);
}
return dataSourceMap;
}
return null;
}
解析完后datasources就加载到Environment中了
3、重构获取connection的方法
创建和获取连接时通过JdbcTransaction的getConnection方法获取的,因此需要重构打开和获取连接的方法。
首先增加dataSourceMap熟悉,在实例化JdbcTransaction对象的时候将dataSourceMap加载进来
protected Map<String, DataSource> dataSourceMap;
public Connection getConnection(String dbKey) throws SQLException {
if (connection == null) {
openConnection(dbKey);
}
return connection;
}
protected void openConnection(String dbKey) throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection, dbKey=" + dbKey);
}
DataSource dataSource = dataSourceMap.get(dbKey);
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
}
4、重现数据库查询,更新操作
查询,更新的方法传入一个dbkey用来指定从哪个数据源进行查询;重构非常简单,将指定的dbkey传递进来即可,代码省略。