轉(zhuǎn)載https://www.cnblogs.com/puretuo/p/11365359.html单起;
一. mybatis plus
?因?yàn)槲覀冺?xiàng)目是springboot+mybatis plus仓手,有些人一看搀玖,mybatis還知道對(duì)吧乳幸,mybatis plus是什么鬼怕品,其實(shí)字面意思可以理解治笨,就是對(duì)mybatis進(jìn)行一些功能改造考婴,一些封裝升級(jí),然后用起來(lái)特別方便杆麸。
? ? ?核心功能的升級(jí)主要是以下三點(diǎn):
? ? ?支持通用的 CRUD搁进、代碼生成器與條件構(gòu)造器。
通用 CRUD:定義好 Mapper 接口后昔头,只需要繼承 BaseMapper 接口即可獲得通用的增刪改查功能饼问,無(wú)需編寫任何接口方法與配置文件
條件構(gòu)造器:通過(guò) EntityWrapper (實(shí)體包裝類),可以用于拼接 SQL 語(yǔ)句揭斧,并且支持排序莱革、分組查詢等復(fù)雜的 SQL
代碼生成器:支持一系列的策略配置與全局配置,比 MyBatis 的代碼生成更好用
二.多數(shù)據(jù)源配置開(kāi)始
? ? 思路:
1讹开、yml中配置多個(gè)數(shù)據(jù)源信息
2盅视、通過(guò)AOP切換不同數(shù)據(jù)源
3、配合mybatis plus使用
1旦万、yml配置
spring:
??aop:
??????proxy-target-class:?true
??????auto:?true
??datasource:
????druid:
??????db1:
????????url: jdbc:mysql://localhost:3306/eboot
????????username: root
????????password: root
????????driver-class-name: com.mysql.jdbc.Driver
????????initialSize:?5
????????minIdle:?5
????????maxActive:?20
??????db2:
????????url: jdbc:oracle:thin:@192.168.136.222:ORCL
????????username: sa
????????password: sa123456
????????driver-class-name: oracle.jdbc.OracleDriver
????????initialSize:?5
????????minIdle:?5
????????maxActive:?20
2闹击、啟動(dòng)多個(gè)數(shù)據(jù)源
@EnableTransactionManagement?//開(kāi)啟事務(wù)
@Configuration?//spring中常用到注解,與xml配置相對(duì)立成艘。是兩種加載bean方式
@MapperScan("com.df.openapi.**.mapper.db*")?// 掃描mapperdao的地址
public?class?MybatisPlusConfig {
????@Bean
????public?PaginationInterceptor paginationInterceptor() {
????????PaginationInterceptor paginationInterceptor =?new?PaginationInterceptor();
//??????? paginationInterceptor.setLocalPage(true); // 由于版本問(wèn)題赏半,有些類可能招不到這個(gè)方法,需要升級(jí)jar包
????????return?paginationInterceptor;
????}
????@Bean(name =?"db1")
????@ConfigurationProperties(prefix =?"spring.datasource.druid.db1")
????public?DataSource db1() {
????????return?DruidDataSourceBuilder.create().build();
????}
????@Bean(name =?"db2")
????@ConfigurationProperties(prefix =?"spring.datasource.druid.db2")
????public?DataSource db2() {
????????return?DruidDataSourceBuilder.create().build();
????}
????/**
?????* 動(dòng)態(tài)數(shù)據(jù)源配置
?????*
?????* @return
?????*/
????@Bean
????@Primary
????public?DataSource multipleDataSource(@Qualifier("db1") DataSource db1,
?????????????????????????????????????????@Qualifier("db2") DataSource db2) {
????????DynamicDataSource dynamicDataSource =?new?DynamicDataSource();
????????Map targetDataSources =?new?HashMap<>();
????????targetDataSources.put(DBTypeEnum.db1.getValue(), db1);
????????targetDataSources.put(DBTypeEnum.db2.getValue(), db2);
????????dynamicDataSource.setTargetDataSources(targetDataSources);
????????dynamicDataSource.setDefaultTargetDataSource(db2);?// 程序默認(rèn)數(shù)據(jù)源淆两,這個(gè)要根據(jù)程序調(diào)用數(shù)據(jù)源頻次断箫,經(jīng)常把常調(diào)用的數(shù)據(jù)源作為默認(rèn)
????????return?dynamicDataSource;
????}
????@Bean("sqlSessionFactory")
????public?SqlSessionFactory sqlSessionFactory()?throws?Exception {
????????MybatisSqlSessionFactoryBean sqlSessionFactory =?new?MybatisSqlSessionFactoryBean();
????????sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2()));
????????MybatisConfiguration configuration =?new?MybatisConfiguration();
????????configuration.setJdbcTypeForNull(JdbcType.NULL);
????????configuration.setMapUnderscoreToCamelCase(true);
????????configuration.setCacheEnabled(false);
????????sqlSessionFactory.setConfiguration(configuration);
????????//PerformanceInterceptor(),OptimisticLockerInterceptor()
????????//添加分頁(yè)功能
????????sqlSessionFactory.setPlugins(new?Interceptor[]{
????????????????paginationInterceptor()
????????});
//??????? sqlSessionFactory.setGlobalConfig(globalConfiguration()); //注釋掉全局配置,因?yàn)樵趚ml中讀取就是全局配置
????????return?sqlSessionFactory.getObject();
????}
?/*?? @Bean
????public GlobalConfiguration globalConfiguration() {
????????GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
????????conf.setLogicDeleteValue("-1");
????????conf.setLogicNotDeleteValue("1");
????????conf.setIdType(0);
????????conf.setMetaObjectHandler(new MyMetaObjectHandler());
????????conf.setDbColumnUnderline(true);
????????conf.setRefresh(true);
????????return conf;
????}*/
}
3秋冰、DBType枚舉類
package?com.df.openapi.config.db;
public?enum?DBTypeEnum {
????db1("db1"), db2("db2");
????private?String value;
????DBTypeEnum(String value) {
????????this.value = value;
????}
????public?String getValue() {
????????return?value;
????}
}
4仲义、動(dòng)態(tài)數(shù)據(jù)源決策
package?com.df.openapi.config.db;
import?org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public?class?DynamicDataSource?extends?AbstractRoutingDataSource {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
String datasource = DataSourceContextHolder.getDbType();
LOGGER.debug("使用數(shù)據(jù)源 {}", datasource);
return datasource;
}
}
5、設(shè)置剑勾、獲取數(shù)據(jù)源
public?class?DataSourceContextHolder {
????private?static?final?Logger LOGGER = LoggerFactory.getLogger(DataSourceContextHolder.class);
????private?static?final?ThreadLocal contextHolder =?new?ThreadLocal<>();?//實(shí)際上就是開(kāi)啟多個(gè)線程光坝,每個(gè)線程進(jìn)行初始化一個(gè)數(shù)據(jù)源
????/**
?????* 設(shè)置數(shù)據(jù)源
?????* @param dbTypeEnum
?????*/
????public?static?void?setDbType(DBTypeEnum dbTypeEnum) {
????????contextHolder.set(dbTypeEnum.getValue());
????}
????/**
?????* 取得當(dāng)前數(shù)據(jù)源
?????* @return
?????*/
????public?static?String getDbType() {
????????return?(String) contextHolder.get();
????}
????/**
?????* 清除上下文數(shù)據(jù)
?????*/
????public?static?void?clearDbType() {
????????contextHolder.remove();
????}
}
6、AOP實(shí)現(xiàn)的數(shù)據(jù)源切換
@Order設(shè)置的足夠小是為了讓他先執(zhí)行
/**
?* aop的實(shí)現(xiàn)的數(shù)據(jù)源切換<br> * aop切點(diǎn)甥材,實(shí)現(xiàn)mapper類找尋,找到所屬大本營(yíng)以后性含,如db1Aspect(),則會(huì)調(diào)用<br> * db1()前面之前的操作洲赵,進(jìn)行數(shù)據(jù)源的切換。
?*/
@Component
@Order(value = -100)
@Slf4j
@Aspect
public?class?DataSourceAspect {
????@Pointcut("execution(* com.zwyl.bazhong.dao.mapper.db1..*.*(..))")
????private?void?db1Aspect() {
????}
????@Pointcut("execution(* com.zwyl.bazhong.dao.mapper.db2..*.*(..))")
????private?void?db2Aspect() {
????}
????@Before("db1Aspect()")
????public?void?db1() {
????????log.info("切換到db1 數(shù)據(jù)源...");
????????DataSourceContextHolder.setDbType(DBTypeEnum.db1);
????}
????@Before("db2Aspect()")
????public?void?db2() {
????????log.info("切換到db2 數(shù)據(jù)源...");
????????DataSourceContextHolder.setDbType(DBTypeEnum.db2);
????}
}
7、mapper層結(jié)構(gòu)
8叠萍、寫一個(gè)service測(cè)試一下
@Service
public?class?DictServiceImpl?implements?IDictService {
????@Resource
????private?PtDictMapper ptDictMapper;?//來(lái)自db1
????@Resource
????private?SysDictMapper sysDictMapper;?// 來(lái)自db2
????@Override
????public?void?getById(String id) {
????????PtDict dict = ptDictMapper.selectById("2bf6257fc8fe483c84c1ad7e89d632f6");
????????SysDict sysDict = sysDictMapper.getById("49");
????????System.out.println("123");
????}
}
9芝发、測(cè)試結(jié)果
總結(jié): 其實(shí)整個(gè)過(guò)程可以理解成,配置多數(shù)據(jù)源 xml中 ?-------> 然后通過(guò)加載多數(shù)源到spring工廠中-------->然后創(chuàng)建多線程苛谷,每個(gè)數(shù)據(jù)源對(duì)應(yīng)一個(gè)數(shù)據(jù)源--------->然后實(shí)際調(diào)用時(shí)候辅鲸,會(huì)先通過(guò)aop匹配到某一具體數(shù)據(jù)源------------->然后實(shí)例化當(dāng)前數(shù)據(jù)源