項目git地址:Jacob-dynamic
準備工作
# 創建數據庫db1
CREATE DATABASE `db1`CHARACTER SET utf8 COLLATE utf8_bin
# 創建user表
CREATE TABLE `user` (`id` int(11) DEFAULT NULL,`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 添加數據
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (1, 'db1_1');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (2, 'db1_2');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (3, 'db1_3');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (4, 'db1_4');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (5, 'db1_5'); # 創建數據庫db2
CREATE DATABASE `db2`CHARACTER SET utf8 COLLATE utf8_bin
# 創建user表
CREATE TABLE `user` (`id` int(11) DEFAULT NULL,`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 添加數據
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (1, 'db2_1');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (2, 'db2_2');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (3, 'db2_3');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (4, 'db2_4');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (5, 'db2_5');
創建項目
最終目錄結果
添加依賴
<!-- mysql start --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- mysql end --><!-- web start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- web end --><!-- lombok start --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- lombok end --><!-- hutool start --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.versiont}</version></dependency><!-- hutool end --><!-- configuration start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><!-- configuration end --><!-- swagger start --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.9.6</version></dependency><!-- swagger end --><!-- mybatis-plus start --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.0</version></dependency><!-- mybatis-plus end --><!-- spring aop start --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- spring aop end -->
添加配置
server:port: 8085spring:datasource:db1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456hikari:maximum-pool-size: 20minimum-idle: 2url: jdbc:mysql://localhost:3306/springbootdb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghaidb2:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456hikari:maximum-pool-size: 20minimum-idle: 2url: jdbc:mysql://localhost:3306/springbootdb2?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
定義枚舉
package cn.org.jacob.enums;
//...
public enum DataSourceTypeEnum {DB1,DB2
}
編寫aop
package cn.org.jacob.aop;
//...
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {DataSourceTypeEnum value() default DataSourceTypeEnum.DB1;}
package cn.org.jacob.aop;
//...
@Slf4j
@Aspect
@Component
@Order(-1)
public class DataSourceAspect {@Pointcut("@annotation(cn.org.jacob.aop.DataSource)")public void dataSourceAspectMethod() {}@Before(value = "dataSourceAspectMethod()")public void beforeDataSource(JoinPoint joinPoint) {
// log.info("進入切點>>>>>>>>>>>>>>>>>>>>>>>>>>>執行切換數據源");MethodSignature signature = (MethodSignature) joinPoint.getSignature();DataSource annotation = signature.getMethod().getAnnotation(DataSource.class);DataSourceTypeEnum value = annotation.value();DataSourceContextHolder.setDataSource(value);log.info("當前使用的數據源:{}", value);}@After("dataSourceAspectMethod()")public void afterDataSource() {DataSourceContextHolder.clear();}
}
package cn.org.jacob.aop;
//...
public class DataSourceContextHolder {/*** 吧數據源存放當前線程*/private static final ThreadLocal<DataSourceTypeEnum> contextHolder = new ThreadLocal<>();/*** 設置數據源** @param dataSource 當前的數據源*/public static void setDataSource(DataSourceTypeEnum dataSource) {contextHolder.set(dataSource);}/*** 獲取數據源** @return 當前數據源*/public static DataSourceTypeEnum getDataSource() {return contextHolder.get();}/*** 刪除當前線程上下文的數據源信息*/public static void clear() {contextHolder.remove();}}
編寫配置
package cn.org.jacob.config;
//..
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("cn.org.jacob")).paths(PathSelectors.any()).build();}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("swagger-bootstrap-ui RESTful APIs").description("swagger-bootstrap-ui").termsOfServiceUrl("http://localhost:8081/").contact("m15870979735@163.com").version("1.0").build();}
}
package cn.org.jacob.config;
//..
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.db1")
public class Db1Config {private String driverClassName;private String userName;private String password;private String url;}
package cn.org.jacob.config;
//..
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.db2")
public class Db2Config {private String driverClassName;private String userName;private String password;private String url;
}
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSource();}
}
package cn.org.jacob.config;
//..
@Configuration
@MapperScan("cn.org.jacob.mapper")
@Slf4j
public class MybatisPlusConfigurer {@AutowiredDb1Config db1Config;@AutowiredDb2Config db2Config;/*** 分頁插件** @return PaginationInterceptor*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();}@Primary@Bean(value = "db1DataSource")public DataSource roadDataSource() {return DataSourceBuilder.create().url(db1Config.getUrl()).driverClassName(db1Config.getDriverClassName()).username(db1Config.getUserName()).password(db1Config.getPassword()).type(HikariDataSource.class).build();}@Bean(value = "db2DataSource")public DataSource garageDataSource() {return DataSourceBuilder.create().url(db2Config.getUrl()).driverClassName(db2Config.getDriverClassName()).username(db2Config.getUserName()).password(db2Config.getPassword()).type(HikariDataSource.class).build();}@Beanpublic DynamicDataSource dataSource(@Qualifier("db1DataSource") DataSource db1DataSource,@Qualifier("db2DataSource") DataSource db2DataSource) {Map<Object, Object> map = new HashMap<>(2);map.put(DataSourceTypeEnum.DB1, db1DataSource);map.put(DataSourceTypeEnum.DB2, db2DataSource);DynamicDataSource dynamicDataSource = new DynamicDataSource();dynamicDataSource.setTargetDataSources(map);dynamicDataSource.setDefaultTargetDataSource(db1DataSource);return dynamicDataSource;}@Beanpublic MybatisSqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();// 重新設置數據源 DB1,DB2 兩個sqlSessionFactoryBean.setDataSource(dataSource(roadDataSource(), garageDataSource()));Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");sqlSessionFactoryBean.setMapperLocations(resources);// 手動設置分頁插件sqlSessionFactoryBean.setPlugins(new Interceptor[] { paginationInterceptor() });return sqlSessionFactoryBean;}@Beanpublic PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {return new DataSourceTransactionManager(dynamicDataSource);}
}
實體類,Mapper,service忽略
編寫控制器
@RestController
@Slf4j
@Api(value = "用戶", tags = {"用戶"})
@AllArgsConstructor
@RequestMapping("user")
public class UserController {private UserService userService;@GetMapping("db1List")@ApiOperation(value = "獲取db1List")@DataSource(DataSourceTypeEnum.DB1)public List<User> db1List(){return userService.list();}@GetMapping("db2List")@ApiOperation(value = "獲取db2List")@DataSource(DataSourceTypeEnum.DB2)public List<User> db2List(){return userService.list();}}