SpringBoot 版本為1.5.10.RELEASE,Mybatis plus 版本為2.1.8。
第一步:填寫配置信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
spring: aop: proxy-target-class: true auto: true datasource: druid: # 數據庫 1 db1: url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true username: root password: root driver-class-name: com.mysql.jdbc.Driver initialSize: 5 minIdle: 5 maxActive: 20 # 數據庫 2 db2: url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true username: root password: root driver-class-name: com.mysql.jdbc.Driver initialSize: 5 minIdle: 5 maxActive: 20 |
第二步: 數據源配置:
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
74
75
76
77
78
79
80
81
82
|
@Configuration @MapperScan ({ "com.warm.system.mapper*" }) public class MybatisPlusConfig { /** * mybatis-plus分頁插件<br> * 文檔:http://mp.baomidou.com<br> */ @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); //paginationInterceptor.setLocalPage(true);// 開啟 PageHelper 的支持 return paginationInterceptor; } /** * mybatis-plus SQL執行效率插件【生產環境可以關閉】 */ @Bean public PerformanceInterceptor performanceInterceptor() { return new PerformanceInterceptor(); } @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(); } /** * 動態數據源配置 * @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(db1); return dynamicDataSource; } @Bean ( "sqlSessionFactory" ) public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2())); //sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*/*Mapper.xml")); MybatisConfiguration configuration = new MybatisConfiguration(); //configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase( true ); configuration.setCacheEnabled( false ); sqlSessionFactory.setConfiguration(configuration); sqlSessionFactory.setPlugins( new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor() paginationInterceptor() //添加分頁功能 }); sqlSessionFactory.setGlobalConfig(globalConfiguration()); 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; } } |
第三步:利用AOP進行數據源的動態切換:
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
74
75
76
|
@Component @Aspect @Order (- 100 ) //這是為了保證AOP在事務注解之前生效,Order的值越小,優先級越高 @Slf4j public class DataSourceSwitchAspect { @Pointcut ( "execution(* com.warm.system.service.db1..*.*(..))" ) private void db1Aspect() { } @Pointcut ( "execution(* com.warm.system.service.db2..*.*(..))" ) private void db2Aspect() { } @Before ( "db1Aspect()" ) public void db1() { log.info( "切換到db1 數據源..." ); DbContextHolder.setDbType(DBTypeEnum.db1); } @Before ( "db2Aspect()" ) public void db2 () { log.info( "切換到db2 數據源..." ); DbContextHolder.setDbType(DBTypeEnum.db2); } } public class DbContextHolder { private static final ThreadLocal contextHolder = new ThreadLocal<>(); /** * 設置數據源 * @param dbTypeEnum */ public static void setDbType(DBTypeEnum dbTypeEnum) { contextHolder.set(dbTypeEnum.getValue()); } /** * 取得當前數據源 * @return */ public static String getDbType() { return (String) contextHolder.get(); } /** * 清除上下文數據 */ public static void clearDbType() { contextHolder.remove(); } } public enum DBTypeEnum { db1( "db1" ), db2( "db2" ); private String value; DBTypeEnum(String value) { this .value = value; } public String getValue() { return value; } } public class DynamicDataSource extends AbstractRoutingDataSource { /** * 取得當前使用哪個數據源 * @return */ @Override protected Object determineCurrentLookupKey() { return DbContextHolder.getDbType(); } } |
OK!寫個單元測試來驗證一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@SpringBootTest @RunWith (SpringJUnit4ClassRunner. class ) public class DataTest { @Autowired private UserService userService; @Autowired private OrderService orderService; @Test public void test() { userService.getUserList().stream().forEach(item -> System.out.println(item)); orderService.getOrderList().stream().forEach(item -> System.out.println(item)); } } |
如圖所示,證明數據源能動態切換了。
具體項目結構和代碼參考Github。
踩坑記錄:
直接調用Mybatis plus 的service方法AOP不會生效,即數據源不會動態切換,解決方法:在自己的service層中封裝一下,調用自定義的service方法AOP即能正常生效了,如下所示:
1
2
3
4
5
6
7
8
|
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Override public List<User> getUserList() { return selectList( null ); } } |
application.yml 定義的mybatis plus 配置信息不生效,如:
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
|
#MyBatis mybatis-plus: mapper-locations: classpath:/mapper/*/*Mapper.xml #實體掃描,多個package用逗號或者分號分隔 typeAliasesPackage: com.jinhuatuo.edu.sys.entity global-config: #主鍵類型 0:"數據庫ID自增", 1:"用戶輸入ID",2:"全局唯一ID (數字類型唯一ID)", 3:"全局唯一ID UUID"; id-type: 0 #字段策略 0:"忽略判斷",1:"非 NULL 判斷"),2:"非空判斷" field-strategy: 2 #駝峰下劃線轉換 db-column-underline: true #刷新mapper 調試神器 refresh-mapper: true #數據庫大寫下劃線轉換 #capital-mode: true #序列接口實現類配置 #key-generator: com.baomidou.springboot.xxx #邏輯刪除配置 #logic-delete-value: 0 #logic-not-delete-value: 1 #自定義填充策略接口實現 meta-object-handler: com.jinhuatuo.edu.config.mybatis.MyMetaObjectHandler #自定義SQL注入器 #sql-injector: com.baomidou.springboot.xxx configuration: map-underscore-to-camel-case: true cache-enabled: false |
解決方法: 所有這些配置在MybatisPlusConfig 類中用代碼的方式進行配置,分頁插件亦是如此,否則統計列表總數的數據會拿不到,參考代碼即可。
在application.yml配置
1
2
|
logging: level: debug |
控制臺也不會打印Mybatis 執行的SQL語句,解決方法:自定義日志輸出方案,如在classpath下直接引入日志配置文件如logback-spring.xml即可,同時application.yml無需再配置日志信息。
logback-spring.xml配置參考:
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
<? xml version = "1.0" encoding = "UTF-8" ?> <!-- scan:配置文件如果發生改變,將會重新加載,默認值為true --> < configuration scan = "true" scanPeriod = "10 seconds" > <!-- <include resource="org/springframework/boot/logging/logback/base.xml"/> --> <!-- 日志文件路徑 --> <!-- <springProperty name="logFilePath" source="logging.path"/> --> < property resource = "application.yml" /> < substitutionProperty name = "LOG_HOME" value = "${logging.path}" /> < substitutionProperty name = "PROJECT_NAME" value = "${spring.application.name}" /> <!--<substitutionProperty name="CUR_NODE" value="${info.node}" />--> <!-- 日志數據庫路徑 --> <!-- <springProperty name="logDbPath" source="spring.datasource.one.url"/> <springProperty name="logDbDriver" source="spring.datasource.one.driver-class-name"/> <springProperty name="logDbUser" source="spring.datasource.one.username"/> <springProperty name="logDbPwd" source="spring.datasource.one.password"/> --> <!-- 將日志文件 --> < appender name = "file" class = "ch.qos.logback.core.rolling.RollingFileAppender" > < append >true</ append > < encoder > < pattern > [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n </ pattern > < charset >utf-8</ charset > </ encoder > < rollingPolicy class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > < fileNamePattern >${LOG_HOME}/${PROJECT_NAME}-%d{yyyy-MM-dd}.%i.log</ fileNamePattern > < timeBasedFileNamingAndTriggeringPolicy class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" > < maxFileSize >50 MB</ maxFileSize > </ timeBasedFileNamingAndTriggeringPolicy > <!--最多保留30天log--> < maxHistory >30</ maxHistory > </ rollingPolicy > </ appender > <!-- 將日志錯誤文件--> < appender name = "file_error" class = "ch.qos.logback.core.rolling.RollingFileAppender" > < append >true</ append > < encoder > < pattern > [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n </ pattern > < charset >utf-8</ charset > </ encoder > < rollingPolicy class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > < fileNamePattern >${LOG_HOME}/${PROJECT_NAME}-error-%d{yyyy-MM-dd}.%i.log</ fileNamePattern > < timeBasedFileNamingAndTriggeringPolicy class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" > < maxFileSize >50 MB</ maxFileSize > </ timeBasedFileNamingAndTriggeringPolicy > <!--最多保留30天log--> < maxHistory >30</ maxHistory > </ rollingPolicy > < filter class = "ch.qos.logback.classic.filter.ThresholdFilter" > < level >ERROR</ level > <!-- <onMatch>ACCEPT</onMatch> <onMismatch>DENY </onMismatch> --> </ filter > </ appender > <!-- 將日志寫入控制臺 --> < appender name = "console" class = "ch.qos.logback.core.ConsoleAppender" > < encoder > < pattern > [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n </ pattern > <!--<charset>utf-8</charset>--> </ encoder > </ appender > <!-- 將日志寫入數據庫 --> <!-- <appender name="DB-CLASSIC-MYSQL-POOL" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DataSourceConnectionSource"> <dataSource class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <driverClassName>${logDbDriver}</driverClassName> <url>${logDbPath}</url> <username>${logDbUser}</username> <password>${logDbPwd}</password> </dataSource> </connectionSource> </appender> --> <!-- spring擴展,分環境配置log信息 --> < springProfile name = "dev" > <!-- <logger name="sand.dao" level="DEBUG"/> --> <!-- <logger name="org.springframework.web" level="INFO"/> --> < logger name = "org.springboot.sample" level = "TRACE" /> < logger name = "org.springframework.cloud" level = "INFO" /> < logger name = "com.netflix" level = "INFO" ></ logger > < logger name = "org.springframework.boot" level = "INFO" ></ logger > < logger name = "org.springframework.web" level = "INFO" /> < logger name = "jdbc.sqltiming" level = "debug" /> < logger name = "com.ibatis" level = "debug" /> < logger name = "com.ibatis.common.jdbc.SimpleDataSource" level = "debug" /> < logger name = "com.ibatis.common.jdbc.ScriptRunner" level = "debug" /> < logger name = "com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level = "debug" /> < logger name = "java.sql.Connection" level = "debug" /> < logger name = "java.sql.Statement" level = "debug" /> < logger name = "java.sql.PreparedStatement" level = "debug" /> < logger name = "java.sql.ResultSet" level = "debug" /> < logger name = "com.warm" level = "debug" /> < root level = "DEBUG" > < appender-ref ref = "console" /> < appender-ref ref = "file" /> </ root > < root level = "ERROR" > < appender-ref ref = "file_error" /> <!-- <appender-ref ref="DB-CLASSIC-MYSQL-POOL" /> --> </ root > </ springProfile > < springProfile name = "test" > < logger name = "org.springboot.sample" level = "TRACE" /> < logger name = "org.springframework.cloud" level = "INFO" /> < logger name = "com.netflix" level = "INFO" ></ logger > < logger name = "org.springframework.boot" level = "INFO" ></ logger > < logger name = "org.springframework.web" level = "INFO" /> < logger name = "jdbc.sqltiming" level = "debug" /> < logger name = "com.ibatis" level = "debug" /> < logger name = "com.ibatis.common.jdbc.SimpleDataSource" level = "debug" /> < logger name = "com.ibatis.common.jdbc.ScriptRunner" level = "debug" /> < logger name = "com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level = "debug" /> < logger name = "java.sql.Connection" level = "debug" /> < logger name = "java.sql.Statement" level = "debug" /> < logger name = "java.sql.PreparedStatement" level = "debug" /> < logger name = "java.sql.ResultSet" level = "debug" /> < logger name = "com.warm" level = "DEBUG" /> < root level = "DEBUG" > <!-- <appender-ref ref="console" /> --> < appender-ref ref = "file" /> </ root > < root level = "ERROR" > < appender-ref ref = "file_error" /> <!-- <appender-ref ref="DB-CLASSIC-MYSQL-POOL" /> --> </ root > </ springProfile > < springProfile name = "prod" > < logger name = "org.springboot.sample" level = "TRACE" /> < logger name = "org.springframework.cloud" level = "INFO" /> < logger name = "com.netflix" level = "INFO" ></ logger > < logger name = "org.springframework.boot" level = "INFO" ></ logger > < logger name = "org.springframework.web" level = "INFO" /> < logger name = "jdbc.sqltiming" level = "debug" /> < logger name = "com.ibatis" level = "debug" /> < logger name = "com.ibatis.common.jdbc.SimpleDataSource" level = "debug" /> < logger name = "com.ibatis.common.jdbc.ScriptRunner" level = "debug" /> < logger name = "com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate" level = "debug" /> < logger name = "java.sql.Connection" level = "debug" /> < logger name = "java.sql.Statement" level = "debug" /> < logger name = "java.sql.PreparedStatement" level = "debug" /> < logger name = "java.sql.ResultSet" level = "debug" /> < logger name = "com.warm" level = "info" /> < root level = "DEBUG" > <!-- <appender-ref ref="console" /> --> < appender-ref ref = "file" /> </ root > < root level = "ERROR" > < appender-ref ref = "file_error" /> <!-- <appender-ref ref="DB-CLASSIC-MYSQL-POOL" /> --> </ root > </ springProfile > </ configuration > |
到此這篇關于SpringBoot+Mybatis plus實現多數據源整合的實踐的文章就介紹到這了,更多相關SpringBoot+Mybatis plus多數據源內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/u012075383/article/details/79304178