博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring 配置多数据源
阅读量:7142 次
发布时间:2019-06-29

本文共 15399 字,大约阅读时间需要 51 分钟。

hot3.png

最近用到了MyBatis配置多数据源,原以为简单配置下就行了,实际操作后发现还是要费些事的,这里记录下,以作备忘

不多废话,直接上代码,后面会有简单的实现介绍

jdbc和log4j的配置

复制代码
#定义输出格式ConversionPattern=%d %-5p [%t] %c - %m%nlog4j.rootLogger=DEBUG,Consolelog4j.logger.com.cnblogs.lzrabbit=DEBUGlog4j.logger.org.springframework=ERRORlog4j.logger.org.mybatis=ERRORlog4j.logger.org.apache.ibatis=ERRORlog4j.logger.org.quartz=ERRORlog4j.logger.org.apache.axis2=ERRORlog4j.logger.org.apache.axiom=ERRORlog4j.logger.org.apache=ERRORlog4j.logger.httpclient=ERROR#log4j.additivity.org.springframework=false#Console log4j.appender.Console=org.apache.log4j.ConsoleAppenderlog4j.appender.Console.Threshold=DEBUG  log4j.appender.Console.Target=System.out  log4j.appender.Console.layout=org.apache.log4j.PatternLayout  log4j.appender.Console.layout.ConversionPattern=${ConversionPattern}#log4j.appender.Console.encoding=UTF-8#org.apache.log4j.DailyRollingFileAppenderlog4j.appender.DailyFile=org.apache.log4j.DailyRollingFileAppenderlog4j.appender.DailyFile.DatePattern='.'yyyy-MM-dd'.log'log4j.appender.DailyFile.File=${myApp.root}/logs/daily.loglog4j.appender.DailyFile.Append=truelog4j.appender.DailyFile.Threshold=DEBUGlog4j.appender.DailyFile.layout=org.apache.log4j.PatternLayoutlog4j.appender.DailyFile.layout.ConversionPattern=${ConversionPattern}log4j.appender.DailyFile.encoding=UTF-8#    %c 输出日志信息所属的类的全名 #    %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss},输出类似:2002-10-18- 22:10:28#    %f 输出日志信息所属的类的类名 #    %l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行 #    %m 输出代码中指定的信息,如log(message)中的message #    %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n” #    %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推 #    %r 输出自应用启动到输出该日志信息所耗费的毫秒数 #    %t 输出产生该日志事件的线程名
复制代码
复制代码
#============================================================================# MySQL#============================================================================jdbc.mysql.driver=com.mysql.jdbc.Driverjdbc.mysql.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=truejdbc.mysql.username=rootjdbc.mysql.password=root#============================================================================# MS SQL Server#============================================================================#jdbc.sqlserver.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver#jdbc.sqlserver.url=jdbc:sqlserver://127.0.0.1:1433;database=test;#jdbc.sqlserver.username=sa#jdbc.sqlserver.password=sa#============================================================================# MS SQL Server (JTDS)#============================================================================jdbc.sqlserver.driver=net.sourceforge.jtds.jdbc.Driverjdbc.sqlserver.url=jdbc:jtds:sqlserver://127.0.0.1:1433/testjdbc.sqlserver.username=sajdbc.sqlserver.password=sa#============================================================================# 通用配置#============================================================================jdbc.initialSize=5jdbc.minIdle=5jdbc.maxIdle=20jdbc.maxActive=100jdbc.maxWait=100000jdbc.defaultAutoCommit=falsejdbc.removeAbandoned=truejdbc.removeAbandonedTimeout=600jdbc.testWhileIdle=truejdbc.timeBetweenEvictionRunsMillis=60000jdbc.numTestsPerEvictionRun=20jdbc.minEvictableIdleTimeMillis=300000
复制代码

单数据源时的Spring配置文件

复制代码
复制代码

多数据源时Spring配置文件

复制代码
复制代码

MultipleDataSource实现

复制代码
package com.cnblogs.lzrabbit;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * Created by rabbit on 14-5-25. */public class MultipleDataSource extends AbstractRoutingDataSource {    private static final ThreadLocal
dataSourceKey = new InheritableThreadLocal
(); public static void setDataSourceKey(String dataSource) { dataSourceKey.set(dataSource); } @Override protected Object determineCurrentLookupKey() { return dataSourceKey.get(); }}
复制代码

MyBatis接口Mapper定义,直接使用注解方式实现

复制代码
public interface MySqlMapper {    @Select("select * from MyTable")    List
> getList();}public interface SqlServerMapper { @Select("select * from MyTable") List
> getList();}
复制代码

手动数据源切换调用

复制代码
package com.cnblogs.lzrabbit;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Created by rabbit on 14-5-25. */public class Main {    public static void main(String[] args) {        //初始化ApplicationContext        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");        MySqlMapper mySqlMapper = applicationContext.getBean(MySqlMapper.class);        SqlServerMapper sqlServerMapper = applicationContext.getBean(SqlServerMapper.class);                //设置数据源为MySql,使用了AOP测试时请将下面这行注释        MultipleDataSource.setDataSourceKey("mySqlDataSource");        mySqlMapper.getList();        //设置数据源为SqlServer,使用AOP测试时请将下面这行注释        MultipleDataSource.setDataSourceKey("sqlServerDataSource");        sqlServerMapper.getList();    }}
复制代码

使用SpringAOP方式实现自动切换

复制代码
package com.cnblogs.lzrabbit;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.springframework.stereotype.Component;@Component@Aspectpublic class MultipleDataSourceAspectAdvice {    @Around("execution(* com.cnblogs.lzrabbit.*.*(..))")    public Object doAround(ProceedingJoinPoint jp) throws Throwable {        if (jp.getTarget() instanceof MySqlMapper) {            MultipleDataSource.setDataSourceKey("mySqlDataSource");        } else if (jp.getTarget() instanceof SqlServerMapper) {            MultipleDataSource.setDataSourceKey("sqlServerDataSource");        }        return jp.proceed();    }}
复制代码

调用日志

复制代码
2014-05-25 20:02:04,319 DEBUG [main] com.cnblogs.lzrabbit.MySqlMapper.getList - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true, UserName=root@192.168.1.32, MySQL Connector Java]2014-05-25 20:02:04,333 DEBUG [main] com.cnblogs.lzrabbit.MySqlMapper.getList - ==>  Preparing: select * from MyTable 2014-05-25 20:02:04,371 DEBUG [main] com.cnblogs.lzrabbit.MySqlMapper.getList - ==> Parameters: 2014-05-25 20:02:04,396 DEBUG [main] com.cnblogs.lzrabbit.MySqlMapper.getList - <==      Total: 82014-05-25 20:02:04,620 DEBUG [main] com.cnblogs.lzrabbit.SqlServerMapper.getList - ooo Using Connection [jdbc:jtds:sqlserver://127.0.0.1:1433/test, UserName=sa, jTDS Type 4 JDBC Driver for MS SQL Server and Sybase]2014-05-25 20:02:04,620 DEBUG [main] com.cnblogs.lzrabbit.SqlServerMapper.getList - ==>  Preparing: select * from TmallCityMap 2014-05-25 20:02:04,621 DEBUG [main] com.cnblogs.lzrabbit.SqlServerMapper.getList - ==> Parameters: 2014-05-25 20:02:04,681 DEBUG [main] com.cnblogs.lzrabbit.SqlServerMapper.getList - <==      Total: 397
复制代码

这里就上面的实现做个简单解释,在我们配置单数据源时可以看到数据源类型使用了org.apache.commons.dbcp.BasicDataSource,而这个代码实现了javax.sql.DataSource接口

配置sqlSessionFactory时org.mybatis.spring.SqlSessionFactoryBean注入参数dataSource类型就是javax.sql.DataSource

实现多数据源的方法就是我们自定义了一个MultipleDataSource,这个类继承自AbstractRoutingDataSource,而AbstractRoutingDataSource继承自AbstractDataSource ,AbstractDataSource 实现了javax.sql.DataSource接口,所以我们的MultipleDataSource也实现了javax.sql.DataSource接口,可以赋值给sqlSessionFactory的dataSource属性

复制代码
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {}public abstract class AbstractDataSource implements DataSource {}
复制代码

  再来说下MultipleDataSource的实现原理,MultipleDataSource实现AbstractRoutingDataSource抽象类,然后实现了determineCurrentLookupKey方法,这个方法用于选择具体使用targetDataSources中的哪一个数据源

复制代码
复制代码

可以看到Spring配置中multipleDataSource设置了两个属性defaultTargetDataSource和targetDataSources,这两个属性定义在AbstractRoutingDataSource,当MyBatis执行查询时会先选择数据源,选择顺序时现根据determineCurrentLookupKey方法返回的值到targetDataSources中去找,若能找到怎返回对应的数据源,若找不到返回默认的数据源defaultTargetDataSource,具体参考AbstractRoutingDataSource的源码

复制代码
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {    private Map
targetDataSources; private Object defaultTargetDataSource; /** * Retrieve the current target DataSource. Determines the * {
@link #determineCurrentLookupKey() current lookup key}, performs * a lookup in the {
@link #setTargetDataSources targetDataSources} map, * falls back to the specified * {
@link #setDefaultTargetDataSource default target DataSource} if necessary. * @see #determineCurrentLookupKey() */ protected DataSource determineTargetDataSource() { Assert.notNull(this.resolvedDataSources, "DataSource router not initialized"); Object lookupKey = determineCurrentLookupKey(); DataSource dataSource = this.resolvedDataSources.get(lookupKey); if (dataSource == null && (this.lenientFallback || lookupKey == null)) { dataSource = this.resolvedDefaultDataSource; } if (dataSource == null) { throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]"); } return dataSource; } /** * Determine the current lookup key. This will typically be * implemented to check a thread-bound transaction context. *

Allows for arbitrary keys. The returned key needs * to match the stored lookup key type, as resolved by the * {

@link #resolveSpecifiedLookupKey} method. */ protected abstract Object determineCurrentLookupKey();      .............}

复制代码

 在动态切换数据源方法时选择了AOP方式实现,这里实现的简单粗暴,具体应用时根据实际需要灵活变通吧

 

题外话,这里提下SqlServer驱动选择的问题,目前SqlServer的驱动主要有微软的官方驱动和JTDS驱动两种,关于这两个驱动我做过测试,批量更新,在小数据量(100以下)时,JTDS相对微软驱动性能稍微高一点点,在数据量增大时几万到上百万时,微软驱动有着明显优势,所以若对性能比较敏感,建议使用微软驱动,否则随意

微软驱动在Maven库找不到,这点比较郁闷,若使用maven的话还得先安装到本地,这点很不爽

JTDS使用比较方便Maven直接引用即可

相关jar maven引用

复制代码
UTF-8
3.2.7.RELEASE
org.aspectj
aspectjweaver
1.7.2
commons-dbcp
commons-dbcp
1.4
commons-logging
commons-logging
1.1.3
log4j
log4j
1.2.17
org.springframework
spring-core
${org.springframework.version}
org.springframework
spring-beans
${org.springframework.version}
org.springframework
spring-aop
${org.springframework.version}
org.springframework
spring-context
${org.springframework.version}
org.springframework
spring-jdbc
${org.springframework.version}
org.springframework
spring-context-support
${org.springframework.version}
org.springframework
spring-web
${org.springframework.version}
org.springframework
spring-webmvc
${org.springframework.version}
org.springframework
spring-tx
${org.springframework.version}
org.mybatis
mybatis
3.2.4
org.mybatis
mybatis-spring
1.2.2
org.slf4j
slf4j-log4j12
1.7.6
net.sourceforge.jtds
jtds
1.2.8
mysql
mysql-connector-java
5.1.29
复制代码

 

 

转载于:https://my.oschina.net/gaoguofan/blog/753224

你可能感兴趣的文章
超简单七步,解决windows下安装PaddlePaddle的权限错误!
查看>>
Appium框架
查看>>
Jenkins 用户文档(入门)
查看>>
轻松检测Golang并发的数据竞争
查看>>
如何处理错误消息Please install the gcc make perl packages
查看>>
写完这段代码,就被开除了……
查看>>
浅析微信支付:如何使用沙箱环境测试
查看>>
8种常用数组去重方法
查看>>
Java知识点总结(面向对象)
查看>>
Webpack最简单的方式Mock API
查看>>
MySQL 表锁和行锁机制
查看>>
vue 项目要点总结(二)
查看>>
初学mysql语句
查看>>
Servlet第三篇【request和response简介、response的常见应用】
查看>>
nodejs爬取网站图片.....
查看>>
《Lua设计与实现》的作者codedump:学习也要讲究性价比
查看>>
ES6&ES7中的异步之async函数
查看>>
php-rsa 加密解密
查看>>
16 道 JavaScript 基础算法 - freeCodeCamp
查看>>
lozad.js:懒加载神器
查看>>