一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot+Mybatis plus實現多數據源整合的實踐

SpringBoot+Mybatis plus實現多數據源整合的實踐

2022-02-24 00:46書隱辭 Java教程

本文主要介紹了SpringBoot+Mybatis plus實現多數據源整合的實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

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));
    }
}

如圖所示,證明數據源能動態切換了。

SpringBoot+Mybatis plus實現多數據源整合的實踐

具體項目結構和代碼參考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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 韩国女主播一区二区视频 | 欧美a一片xxxx片与善交 | 日本精品一区二区在线播放 | 成人免费国产欧美日韩你懂的 | 日韩小视频在线观看 | 国产精品久久一区 | 高肉h护士办公室play | 成人免费影 | 91最新国产 | 91看片淫黄大片欧美看国产片 | 按摩院已婚妇女中文字幕 | 哇嘎在线精品视频在线观看 | 免费网址视频在线看 | 2021国产麻豆剧传媒新片 | 深夜在线看 | 美女福利视频一区二区 | 亚洲精品国产一区二区三区在 | 亚洲人成伊人成综合网久久 | 欧美视频免费 | 四虎精品免费视频 | 国内精品免费 | 精品视频一区在线观看 | 免费一级片在线观看 | 国产成人久久精品区一区二区 | 午夜久久免影院欧洲 | 很很草 | 国产成人精品一区二区阿娇陈冠希 | 大肥臀风间由美 中文字幕 大东北chinesexxxx露脸 | 青青国产成人久久91网 | 日本视频二区 | 国产婷婷高清在线观看免费 | 91免费高清无砖码区 | 国产精品久久久久无毒 | 91aaa免费免费国产在线观看 | 精品国产原创在线观看视频 | 粗暴hd另类另类 | 亚洲AV无码国产精品午夜久久 | 免费视频亚洲 | 亚洲欧美成人综合久久久 | 国产一区二区免费在线 | 亚洲色图第一页 |