应用场景:
项目需要同时连接多个不同的数据库A, B,并且它们都需要读写操作
项目技术选项:
SpringBoot_ssm
数据库:MySQL 、SQL server
看网上有很多类似笔记,但有些繁琐,这里简单说明,记个笔记。
以此记录:
这里仅仅展示部份关键依赖
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.0.0
mysql
mysql-connector-java
5.1.30
com.microsoft.sqlserver
sqljdbc4
4.0
com.alibaba
druid-spring-boot-starter
1.1.10
#====================数据源MySQL配置===================#
spring.datasource.mysql.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.mysql.url=jdbc\:mysql\://127.0.0.1\:3306/数据库名?useUnicode\=true&characterEncoding\=UTF-8
spring.datasource.mysql.username=账号
spring.datasource.mysql.password=密码
#====================SQL Server=======================#
spring.datasource.sqlserver.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.sqlserver.url=jdbc:sqlserver://127.0.0.1:1433;DatabaseName=xinsong
spring.datasource.sqlserver.username=sa
spring.datasource.sqlserver.password=root
#====================druid连接池=======================#
# 使用druid连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.minIdle= 1
spring.datasource.maxActive=20
# 说明:这里省略其他诸多配置。。。。。
1.创建DataSourceConfig类,主要用于配置所需要用到的数据库
@Configuration
public class DataSourceConfig {
//MySQL作为主数据源(默认数据源)
@Bean(name="mysql")
@Primary// 注意:这里需要该注解声明是默认数据源
@ConfigurationProperties(prefix="spring.datasource.mysql")
public DataSource mysqlDateSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean(name="sqlserver")
@ConfigurationProperties(prefix="spring.datasource.sqlserver")
public DataSource sqlServerDateSource(){
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(mysqlDateSource());
// 配置多数据源
Map
2.duird配置
@Configuration
public class DruidConfig {
@Bean
@ConditionalOnMissingBean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
//白名单
servletRegistrationBean.addInitParameter("allow", "192.168.6.195");
//IP黑名单(存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
servletRegistrationBean.addInitParameter("deny", "192.168.6.73");
//用于登陆的账号密码
servletRegistrationBean.addInitParameter("loginUsername", "admin");
servletRegistrationBean.addInitParameter("loginPassword", "admin");
//是否能重置数据
servletRegistrationBean.addInitParameter("resetEnable", "true");
return servletRegistrationBean;
}
/**
* @Date: 2019/5/29 20:51
* @Description: 注册filter信息,用于拦截
*/
@Bean
public FilterRegistrationBean filterRegistrationBean() {
//创建过滤器
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(new WebStatFilter());
//设置过滤器过滤路径
filterRegistrationBean.addUrlPatterns("/*");
//忽略过滤得形式
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
3.实现AOP动态切换,需要先创建一个注解:@DataSource
创建:
import java.lang.annotation.*;
/**
* @author ttllihao
* @description: AOP切换数据源注解,默认值mysql,即MySQL是默认主数据源
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "mysql";
}
4.动态数据源上下文.
/**
* @author ttllihao
* @description: 动态数据源上下文.
*/
@Component
public class DataSourceContextHolder {
/**
* 线程独立
*/
private static ThreadLocal contextHolder = new ThreadLocal();
public static final String DB_DEFAULT__MySQL = "mysql";
public static final String DB_TYPE_SQLServer = "sqlserver";
public static String getDataBaseType() {
return contextHolder.get();
}
public static void setDataBaseType(String dataBase) {
contextHolder.set(dataBase);
}
public static void clearDataBaseType() {
contextHolder.remove();
}
/**
* @author ttllihao
* @description: 获取数据源名
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private Logger logger = LogManager.getLogger("TestController");
@Override
protected Object determineCurrentLookupKey() {
logger.info("当前数据源:{}"+ DataSourceContextHolder.getDataBaseType());
return DataSourceContextHolder.getDataBaseType();
}
6.最重要的一步
**
* @author ttllihao
* @description: 动态切换数据源类
*/
@Aspect
@Component
@Order(-10)
public class DynamicDataSourceAspect {
private Logger logger = LogManager.getLogger("DynamicDataSourceAspect");
@Before("@annotation(DataSource)")
public void beforeSwitchDS(JoinPoint point){
//获得当前访问的class
Class> className = point.getTarget().getClass();
//获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DB_DEFAULT__MySQL;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
// 判断是否存在@DS注解
if (method.isAnnotationPresent(DataSource.class)) {
DataSource annotation = method.getAnnotation(DataSource.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DataSourceContextHolder.setDataBaseType(dataSource);
}
@After("@annotation(DataSource)")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDataBaseType();
}
}