一、應用場景
我們再開發中經常遇到應用不同數據庫的數據,比如一部分需要使用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,至此配置多數據源成功,動態的切換了數據源。當然配置多數據源還有其他方式,我們下次再約吧!