記得面試時(shí)候,有面試官會(huì)問道,你們多數(shù)據(jù)源是怎么實(shí)現(xiàn)的呀。.......,一陣蒙蔽中,然后說道我們之前項(xiàng)目中,沒有用到多數(shù)據(jù)源。
所幸,目前做得項(xiàng)目中有一個(gè)業(yè)務(wù)邏輯中,用到多個(gè)數(shù)據(jù)庫(kù)數(shù)據(jù)情況,多數(shù)據(jù)源華麗上線。
一. mybatis plus
因?yàn)槲覀冺?xiàng)目是springboot+mybatis plus,有些人一看,mybatis還知道對(duì)吧,mybatis plus是什么鬼,其實(shí)字面意思可以理解,就是對(duì)mybatis進(jìn)行一些功能改造,一些封裝升級(jí),然后用起來特別方便。
核心功能的升級(jí)主要是以下三點(diǎn):
支持通用的 CRUD、代碼生成器與條件構(gòu)造器。
通用 CRUD:定義好 Mapper 接口后,只需要繼承 BaseMapper<T> 接口即可獲得通用的增刪改查功能,無需編寫任何接口方法與配置文件
條件構(gòu)造器:通過 EntityWrapper<T> (實(shí)體包裝類),可以用于拼接 SQL 語(yǔ)句,并且支持排序、分組查詢等復(fù)雜的 SQL
代碼生成器:支持一系列的策略配置與全局配置,比 MyBatis 的代碼生成更好用
二.多數(shù)據(jù)源配置開始
思路:
1、yml中配置多個(gè)數(shù)據(jù)源信息
2、通過AOP切換不同數(shù)據(jù)源
3、配合mybatis plus使用
1、yml配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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ù)源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
@EnableTransactionManagement //開啟事務(wù) @Configuration //spring中常用到注解,與xml配置相對(duì)立。是兩種加載bean方式 @MapperScan ( "com.df.openapi.**.mapper.db*" ) // 掃描mapperdao的地址 @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // paginationInterceptor.setLocalPage(true); // 由于版本問題,有些類可能招不到這個(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<Object, Object> 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枚舉類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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ù)源決策
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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ù)源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public class DataSourceContextHolder { private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceContextHolder. class ); private static final ThreadLocal contextHolder = new ThreadLocal<>(); //實(shí)際上就是開啟多個(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í)行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
/** * 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è)試一下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Service public class DictServiceImpl implements IDictService { @Resource private PtDictMapper ptDictMapper; //來自db1 @Resource private SysDictMapper sysDictMapper; // 來自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è)過程可以理解成,配置多數(shù)據(jù)源 xml中 -------> 然后通過加載多數(shù)源到spring工廠中-------->然后創(chuàng)建多線程,每個(gè)數(shù)據(jù)源對(duì)應(yīng)一個(gè)數(shù)據(jù)源--------->然后實(shí)際調(diào)用時(shí)候,會(huì)先通過aop匹配到某一具體數(shù)據(jù)源------------->然后實(shí)例化當(dāng)前數(shù)據(jù)源
到此這篇關(guān)于Mybatis plus 配置多數(shù)據(jù)源的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Mybatis plus 多數(shù)據(jù)源內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/CryOnMyShoulder/p/12218876.html