参考https://github.com/cmlbeliever/SpringBootLearning/tree/master/DynamicDataSource
以上是github的网址
用到了这里说明springboot的项目已经结尾开始加数据源了~
1.多数据源的类如下
2.配置文件目录如下
3.在配置文件俺application中加入数据源和配置切面拦截的方法
(1)数据源
#read database
read.datasource.driverClassName=com.mysql.jdbc.Driver
read.datasource.url=
read.datasource.username=
read.datasource.password=
read.datasource.maxdle=10
read.datasource.maxWait=10000
read.datasource.minIdle=5
read.datasource.initialSize=5
read.datasource.validation-query=SELECT 1
read.datasource.testWhileIdle=true
read.datasource.timeBetweenEvictionRunsMillis=27800
#write database
write.datasource.driverClassName=com.mysql.jdbc.Driver
write.datasource.url=
write.datasource.username=
write.datasource.password=
write.datasource.maxdle=10
write.datasource.maxWait=10000
write.datasource.minIdle=5
write.datasource.initialSize=5
write.datasource.validation-query=SELECT 1
write.datasource.testWhileIdle=true
write.datasource.timeBetweenEvictionRunsMillis=27800
#mybatis
#待会mybatis类进行文件配置用的路径
db.mybatis.mapper-locations=classpath:com/ewe/*/mapping/*.xml
db.mybatis.configLocation=mybatis/mybatis-config.xml
#aspect 事务切入
dynamicDatasource.strategy.read=get,find,select,login
dynamicDatasource.strategy.write=insert,update,delete,add,regist,create
dynamicDatasource.defaultDataSource=write
以下是mybatis的
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 使全局的映射器启用或禁用缓存。 -->
<setting name="cacheEnabled" value="mybatis" />
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- 是否允许单条sql 返回多个数据集 (取决于驱动的兼容性) default:true -->
<setting name="multipleResultSetsEnabled" value="true" />
<!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
<setting name="useColumnLabel" value="true" />
<!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 default:false -->
<setting name="useGeneratedKeys" value="false" />
<!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分 FULL:全部 -->
<setting name="autoMappingBehavior" value="PARTIAL" />
<!-- 这是默认的执行类型 (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新) -->
<setting name="defaultExecutorType" value="SIMPLE" />
<setting name="defaultStatementTimeout" value="25" />
<setting name="defaultFetchSize" value="100" />
<setting name="safeRowBoundsEnabled" value="false" />
<!-- 使用驼峰命名法转换字段。 -->
<setting name="mapUnderscoreToCamelCase" value="true" />
<!-- 设置本地缓存范围 session:就会有数据的共享 statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
<setting name="localCacheScope" value="SESSION" />
<!-- 默认为OTHER,为了解决oracle插入null报错的问题要设置为NULL -->
<setting name="jdbcTypeForNull" value="NULL" />
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
</settings>
</configuration>
pom依赖
<!-- Aspect -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</dependency>
<!-- StringUtils -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<!-- <scope>provided</scope> -->
</dependency>
首先要创建一个mybatis的的配置加载类
DynamicDataSourceAutoConfiguration.java
package com.ewe.core.datasource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
/**
* 动态数据源自动处理 TransactionProxyFactoryBean
*
* @author Martin
*
*/
public class DynamicDataSourceAutoConfiguration {
@Component("dynamicDataSource")
@Primary
@ConfigurationProperties(prefix = "dynamicDatasource")
public static class DynamicDataSource extends AbstractRoutingDataSource implements ApplicationContextAware {
public static final Map<String, String> DATASOURCE_STRATEGY = new HashMap<>();
private Map<String, String> strategy = new HashMap<>();
private ApplicationContext applicationContext;
private String defaultDataSource;
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
@Override
protected Object resolveSpecifiedLookupKey(Object lookupKey) {
return super.resolveSpecifiedLookupKey(lookupKey);
}
@Override
public void afterPropertiesSet() {
Map<String, DataSource> dataSources = applicationContext.getBeansOfType(DataSource.class);
if (dataSources.size() == 0) {
throw new IllegalStateException("Datasource can not found!!!");
}
// exclude current datasource
Map<Object, Object> targetDataSource = excludeCurrentDataSource(dataSources);
setTargetDataSources(targetDataSource);
// 多数据源方法设置
Iterator<String> it = strategy.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
String[] values = strategy.get(key).split(",");
for (String v : values) {
if (v!=null&&v!="") {
DATASOURCE_STRATEGY.put(v, key);
}
}
}
// 默认数据源设置
setDefaultTargetDataSource(targetDataSource.get(getDefaultDataSource()));
super.afterPropertiesSet();
}
/***
* exclude current Datasource
*
* @param dataSources
* @return
*/
private Map<Object, Object> excludeCurrentDataSource(Map<String, DataSource> dataSources) {
Map<Object, Object> targetDataSource = new HashMap<>();
Iterator<String> keys = dataSources.keySet().iterator();
while (keys.hasNext()) {
String key = keys.next();
if (!(dataSources.get(key) instanceof DynamicDataSource)) {
targetDataSource.put(key, dataSources.get(key));
}
}
return targetDataSource;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public Map<String, String> getStrategy() {
return strategy;
}
public void setStrategy(Map<String, String> strategy) {
this.strategy = strategy;
}
public String getDefaultDataSource() {
return defaultDataSource;
}
public void setDefaultDataSource(String defaultDataSource) {
this.defaultDataSource = defaultDataSource;
}
}
}
2.MybatisConfig的数据库加载
package com.ewe.core.datasource;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
/**
*
* @author Martin
*
*/
@Configuration
public class MybatisConfig {
protected static Log log = LogFactory.getLog(MybatisConfig.class);
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource datasource,
MybatisConfigurationProperties properties) throws Exception {
log.info("*************************sqlSessionFactory:begin***********************" + properties);
VFS.addImplClass(SpringBootVFS.class);
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(datasource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(resolver.getResources(properties.mapperLocations));
// sessionFactory
// .setConfigLocation(new
// PathMatchingResourcePatternResolver().getResource(properties.configLocation));
SqlSessionFactory resultSessionFactory = sessionFactory.getObject();
log.info("*************************sqlSessionFactory:successs:" + resultSessionFactory
+ "***********************" + properties);
return resultSessionFactory;
}
@ConfigurationProperties(prefix = "write.datasource")
@Bean(destroyMethod = "close", name = "write")
public DataSource dataSourceWrite() {
log.info("*************************writedataSource***********************");
BasicDataSource dataSource = new BasicDataSource();
// dataSource.setDriverClassName(properties.driverClassName);
// dataSource.setUrl(properties.url);
// dataSource.setUsername(properties.username);
// dataSource.setPassword(properties.password);
// dataSource.setMaxIdle(properties.maxIdle);
// dataSource.setMaxActive(properties.maxActive);
// dataSource.setMaxWait(properties.maxWait);
// dataSource.setInitialSize(properties.initialSize);
// dataSource.setValidationQuery(properties.validationQuery);
/*dataSource.setRemoveAbandoned(true);
dataSource.setTestWhileIdle(true);
dataSource.setTimeBetweenEvictionRunsMillis(30000);
dataSource.setNumTestsPerEvictionRun(30);
dataSource.setMinEvictableIdleTimeMillis(1800000);*/
return dataSource;
}
@ConfigurationProperties(prefix = "read.datasource")
@Bean(destroyMethod = "close", name = "read")
public DataSource dataSourceRead() {
log.info("*************************readdataSource***********************");
BasicDataSource dataSource = new BasicDataSource();
return dataSource;
}
/**
* 加载mybatis的配置文件
* @author Administrator
*
*/
@ConfigurationProperties(prefix = "db.mybatis")
@Component
public static class MybatisConfigurationProperties {
private String mapperLocations;
private String configLocation;
public String getConfigLocation() {
return configLocation;
}
public void setConfigLocation(String configLocation) {
this.configLocation = configLocation;
}
public String getMapperLocations() {
return mapperLocations;
}
public void setMapperLocations(String mapperLocations) {
this.mapperLocations = mapperLocations;
}
@Override
public String toString() {
return "MybatisConfigurationProperties [typeAliasesPackage=" + "" + ", typeHandlerPackage="
+ "" + ", mapperLocations=" + mapperLocations + ", configLocation=" + configLocation
+ "]";
}
}
}
3.DynamicDataSourceHolder 动态数据源处理
package com.ewe.core.datasource;
/**
* 动态数据源处理
*
* @author Martin
*
*/
public class DynamicDataSourceHolder {
private static ThreadLocal<String> holderDataSource = new ThreadLocal<>();
public static void setDataSource(String dataSource) {
holderDataSource.set(dataSource);
}
public static String getDataSource() {
return holderDataSource.get();
}
public static void clear() {
holderDataSource.remove();
}
}
4.事务代理 TransactionAspect
package com.ewe.core.datasource;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.ewe.core.datasource.DynamicDataSourceAutoConfiguration.DynamicDataSource;
/**
* 事务自动代理
* 如果一个services执行多条语句,那么尽管是查询语句也会从主库查询,因为是以service为事务而不是,而是不是dao
* @author Martin
*
*/
@Order(1)
@Aspect()
@EnableAspectJAutoProxy
@Component
public class TransactionAspect {
protected static Log logger = LogFactory.getLog(TransactionAspect.class);
@Pointcut("execution(* com.ewe.*.service.impl.*.*(..))")
public void aspect() {
}
/**
* 配置前置通知,使用在方法aspect()上注册的切入点
*
*/
@Before("aspect()")
public void before(JoinPoint point) {
String className = point.getTarget().getClass().getName();
String method = point.getSignature().getName();
logger.info(className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")");
try {
// 根据方法获取对应的数据源
for (String key : DynamicDataSource.DATASOURCE_STRATEGY.keySet()) {
if (StringUtils.startsWith(method, key)) {
DynamicDataSourceHolder.setDataSource(DynamicDataSource.DATASOURCE_STRATEGY.get(key));
logger.info("---------find datasource ==>" + key + ",datasource:" + DynamicDataSourceHolder.getDataSource()+"-------------");
break;
}
}
} catch (Exception e) {
logger.error(e.toString());
// DynamicDataSourceHolder.setDataSource("write");
}
}
@After("aspect()")
public void after(JoinPoint point) {
DynamicDataSourceHolder.clear();
}
}