一、应用场景
我们再开发中经常遇到应用不同数据库的数据,比如一部分需要使用Mysql下的数据库,一部分需要使用Sql Server的数据库,主从库分离等等。这是需要我们配置多数据源来满足开发需要。
传送门:项目下载地址
二、多数据源
1、引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
2、application.properties配置
server.port=8090
spring.datasource.db1.url=jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.db1.username=root
spring.datasource.db1.password=123456
spring.datasource.db1.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.db1.max-idle=10
spring.datasource.db1.max-wait=10000
spring.datasource.db1.min-idle=5
spring.datasource.db1.initial-size=5
spring.datasource.db2.url=jdbc:mysql://127.0.0.1:3306/db2?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.db2.username=root
spring.datasource.db2.password=123456
spring.datasource.db2.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.db2.max-idle=10
spring.datasource.db2.max-wait=10000
spring.datasource.db2.min-idle=5
spring.datasource.db2.initial-size=5
#mybatis
mybatis.mapper-locations=classpath*:mapper/*.xml
mybatis.type-aliases-package=com.springboot.mapper
3、创建model、mapper、service、controller相关包类
@RestController
@RequestMapping("article")
public class ArticleController {
@Autowired
private ArticleService articleService;
@RequestMapping("arts")
public List<Article> getArtList() {
List<Article> arts =articleService.getArticleList();
return arts;
}
}
/**
* @author: william
* @Description: TODO
* @date: 2018年5月26日 上午10:16:43
* @version: v1.0.0
*/
@RestController
@RequestMapping("label")
public class LabelController {
@Autowired
private LabelService labelService;
@RequestMapping("/{labid}")
public Label getLabelByid(@PathVariable int labid) {
return labelService.getLabelByid(labid);
}
}
-----------service-------------------------
@Service
public class ArticleService {
@Autowired
private ArticleMapper articleMapper;
@Datasource("db1") //自定义注解,指明使用数据源
public List<Article> getArticleList(){
return articleMapper.getArticleList();
}
}
@Service
public class LabelService {
@Autowired
private LabelMapper labelMapper;
@Datasource("db2")
public Label getLabelByid(int labid) {
return labelMapper.getLabelByid(labid);
}
}
model、mapper就省略了
4、关键点,下面是数据源配置
/**
* @author: william
* @Description: 多数据源初始化配置类
* @date: 2018年5月26日 上午10:39:36
* @version: v1.0.0
*/
@Configuration
public class DataSourceConfig {
//数据源1
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.db1") // application.properteis中对应属性的前缀
public DataSource db1() {
return DataSourceBuilder.create().build();
}
//数据源2
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource db2() {
return DataSourceBuilder.create().build();
}
/**
* 利用AOP在不同数据源动态切换
* @return
*/
@Primary
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(db1());
// 多数据源
Map<Object, Object> dsMap = new HashMap();
dsMap.put("db1", db1());
dsMap.put("db2", db2());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
/**
* 配置@Transactional注解事物
* @return
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
public class DataSourceContextHolder {
public static final String DEFAULT_DS = "db1";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
// 设置数据源名
public static void setDB(String dbType) {
System.out.println("===========使用"+dbType+"数据源");
contextHolder.set(dbType);
}
// 获取数据源
public static String getDB() {
return (contextHolder.get());
}
// 清除数据源
public static void clearDB() {
contextHolder.remove();
}
}
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
System.out.println("数据源为"+DataSourceContextHolder.getDB());
return DataSourceContextHolder.getDB();
}
}
@Aspect
@Component
public class DynamicDataSourceAspect {
/**
* 通过AOP前置通知,利用注解切换数据源
* @param point
*/
@Before("@annotation(Datasource)")
public void beforeSwitchDS(JoinPoint point){
Class<?> className = point.getTarget().getClass();
String methodName = point.getSignature().getName();
//得到方法的参数
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
// 反射得到方法对象
Method method = className.getMethod(methodName, argClass);
//判断是否使用@Datasource注解
if (method.isAnnotationPresent(Datasource.class)) {
Datasource annotation = method.getAnnotation(Datasource.class);
//得到注解上数据源
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
//动态设置数据源
DataSourceContextHolder.setDB(dataSource);
}
@After("@annotation(Datasource)")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDB();
}
}
/**
* 自定义注解,
@Retention定义生命周期
@Target定义作用范围,方法上
*/@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface Datasource { String value() default "db1";}
5、最好注意一点,禁用掉默认的单数据源
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
6、建立mysql数据库
7、demo目录结构
8、启动运行访问,测试多数据源配置是否成功
使用postman调接口返回
artcle数据来自db1,label数据来自db2,至此配置多数据源成功,动态的切换了数据源。当然配置多数据源还有其他方式,我们下次再约吧!