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

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Spring Boot + Mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源案例分析

Spring Boot + Mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源案例分析

2021-06-09 14:08朝雨憶輕塵 Java教程

這篇文章主要介紹了Spring Boot + Mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源,需要的朋友可以參考下

動(dòng)態(tài)數(shù)據(jù)源

在很多具體應(yīng)用場(chǎng)景的時(shí)候,我們需要用到動(dòng)態(tài)數(shù)據(jù)源的情況,比如多租戶(hù)的場(chǎng)景,系統(tǒng)登錄時(shí)需要根據(jù)用戶(hù)信息切換到用戶(hù)對(duì)應(yīng)的數(shù)據(jù)庫(kù)。又比如業(yè)務(wù)a要訪問(wèn)a數(shù)據(jù)庫(kù),業(yè)務(wù)b要訪問(wèn)b數(shù)據(jù)庫(kù)等,都可以使用動(dòng)態(tài)數(shù)據(jù)源方案進(jìn)行解決。接下來(lái),我們就來(lái)講解如何實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源,以及在過(guò)程中剖析動(dòng)態(tài)數(shù)據(jù)源背后的實(shí)現(xiàn)原理。

實(shí)現(xiàn)案例

本教程案例基于 spring boot + mybatis + mysql 實(shí)現(xiàn)。

數(shù)據(jù)庫(kù)設(shè)計(jì)

首先需要安裝好mysql數(shù)據(jù)庫(kù),新建數(shù)據(jù)庫(kù) master,slave,分別創(chuàng)建用戶(hù)表,用來(lái)測(cè)試數(shù)據(jù)源,sql腳本如下。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- ----------------------------------------------------
-- 用戶(hù)
-- ----------------------------------------------------
-- table structure for `sys_user`
-- ----------------------------------------------------
drop table if exists `sys_user`;
create table `sys_user` (
 `id` bigint not null auto_increment comment '編號(hào)',
 `name` varchar(50) not null comment '用戶(hù)名',
 `password` varchar(100) comment '密碼',
 `salt` varchar(40) comment '鹽',
 `email` varchar(100) comment '郵箱',
 `mobile` varchar(100) comment '手機(jī)號(hào)',
 `status` tinyint comment '狀態(tài) 0:禁用 1:正常',
 `dept_id` bigint(20) comment '機(jī)構(gòu)id',
 `create_by` varchar(50) comment '創(chuàng)建人',
 `create_time` datetime comment '創(chuàng)建時(shí)間',
 `last_update_by` varchar(50) comment '更新人',
 `last_update_time` datetime comment '更新時(shí)間',
 `del_flag` tinyint default 0 comment '是否刪除 -1:已刪除 0:正常',
 primary key (`id`),
 unique index (`name`)
) engine=innodb default charset=utf8 comment='用戶(hù)';

新建工程

新建一個(gè)spring boot工程,最終代碼結(jié)構(gòu)如下。

Spring Boot + Mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源案例分析

添加依賴(lài)

添加spring boot,spring aop,mybatis,mysql,swagger相關(guān)依賴(lài)。swagger方便用來(lái)測(cè)試接口。

pom.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
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
   xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelversion>4.0.0</modelversion>
 
 <groupid>top.ivan.demo</groupid>
 <artifactid>springboot-dynamic-datasource</artifactid>
 <version>0.0.1-snapshot</version>
 <packaging>jar</packaging>
 
 <name>springboot-dynamic-datasource</name>
 <description>demo project for spring boot</description>
 
 <parent>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter-parent</artifactid>
  <version>2.0.4.release</version>
  <relativepath/> <!-- lookup parent from repository -->
 </parent>
 
 <properties>
  <project.build.sourceencoding>utf-8</project.build.sourceencoding>
  <project.reporting.outputencoding>utf-8</project.reporting.outputencoding>
  <java.version>1.8</java.version>
  <mybatis.spring.version>1.3.2</mybatis.spring.version>
  <swagger.version>2.8.0</swagger.version>
 </properties>
 
 <dependencies>
   <!-- spring boot -->
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-web</artifactid>
  </dependency>
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-test</artifactid>
   <scope>test</scope>
  </dependency>
  <!-- spring aop -->
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-aop</artifactid>
  </dependency>
  <!-- mybatis -->
  <dependency>
   <groupid>org.mybatis.spring.boot</groupid>
   <artifactid>mybatis-spring-boot-starter</artifactid>
   <version>${mybatis.spring.version}</version>
  </dependency>
  <!-- mysql -->
  <dependency>
   <groupid>mysql</groupid>
   <artifactid>mysql-connector-java</artifactid>
  </dependency>
  <!-- swagger -->
  <dependency>
   <groupid>io.springfox</groupid>
   <artifactid>springfox-swagger2</artifactid>
   <version>${swagger.version}</version>
  </dependency>
  <dependency>
   <groupid>io.springfox</groupid>
   <artifactid>springfox-swagger-ui</artifactid>
   <version>${swagger.version}</version>
  </dependency>
 </dependencies>
 
 <build>
  <plugins>
   <plugin>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-maven-plugin</artifactid>
   </plugin>
  </plugins>
 </build>
 
</project>

配置文件

修改配置文件,添加兩個(gè)數(shù)據(jù)源,可以是同一個(gè)主機(jī)地址的兩個(gè)數(shù)據(jù)庫(kù)master,slave,也可是兩個(gè)不同主機(jī)的地址,根據(jù)實(shí)際情況配置。

application.yml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
 datasource:
 master:
  driver-class-name: com.mysql.jdbc.driver
  type: com.zaxxer.hikari.hikaridatasource
  jdbcurl: jdbc:mysql://127.0.0.1:3306/master?useunicode=true&zerodatetimebehavior=converttonull&autoreconnect=true&characterencoding=utf-8
  username: root
  password: 123
 slave:
  driver-class-name: com.mysql.jdbc.driver
  type: com.zaxxer.hikari.hikaridatasource
  jdbcurl: jdbc:mysql://127.0.0.1:3306/slave?useunicode=true&zerodatetimebehavior=converttonull&autoreconnect=true&characterencoding=utf-8
  username: root
  password: 123

啟動(dòng)類(lèi)

啟動(dòng)類(lèi)添加 exclude = {datasourceautoconfiguration.class}, 以禁用數(shù)據(jù)源默認(rèn)自動(dòng)配置。

數(shù)據(jù)源默認(rèn)自動(dòng)配置會(huì)讀取 spring.datasource.* 的屬性創(chuàng)建數(shù)據(jù)源,所以要禁用以進(jìn)行定制。

@componentscan(basepackages = "com.louis.springboot") 是掃描范圍,都知道不用多說(shuō)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dynamicdatasourceapplication.java
 
package com.louis.springboot.dynamic.datasource;
 
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.boot.autoconfigure.jdbc.datasourceautoconfiguration;
import org.springframework.context.annotation.componentscan;
 
/**
 * 啟動(dòng)器
 * @author louis
 * @date oct 31, 2018
 */
@springbootapplication(exclude = {datasourceautoconfiguration.class}) // 禁用數(shù)據(jù)源自動(dòng)配置
@componentscan(basepackages = "com.louis.springboot")
public class dynamicdatasourceapplication {
 
 public static void main(string[] args) {
  springapplication.run(dynamicdatasourceapplication.class, args);
 }
}

數(shù)據(jù)源配置類(lèi)

創(chuàng)建一個(gè)數(shù)據(jù)源配置類(lèi),主要做以下幾件事情:

1. 配置 dao,model,xml mapper文件的掃描路徑。

2. 注入數(shù)據(jù)源配置屬性,創(chuàng)建master、slave數(shù)據(jù)源。

3. 創(chuàng)建一個(gè)動(dòng)態(tài)數(shù)據(jù)源,并裝入master、slave數(shù)據(jù)源。

4. 將動(dòng)態(tài)數(shù)據(jù)源設(shè)置到sql會(huì)話工廠和事務(wù)管理器。

如此,當(dāng)進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),就會(huì)通過(guò)我們創(chuàng)建的動(dòng)態(tài)數(shù)據(jù)源去獲取要操作的數(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
package com.louis.springboot.dynamic.datasource.config;
 
import java.util.hashmap;
import java.util.map;
 
import javax.sql.datasource;
 
import org.mybatis.spring.sqlsessionfactorybean;
import org.mybatis.spring.annotation.mapperscan;
import org.springframework.boot.context.properties.configurationproperties;
import org.springframework.boot.jdbc.datasourcebuilder;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.context.annotation.primary;
import org.springframework.core.io.support.pathmatchingresourcepatternresolver;
import org.springframework.jdbc.datasource.datasourcetransactionmanager;
import org.springframework.transaction.platformtransactionmanager;
 
import com.louis.springboot.dynamic.datasource.dds.dynamicdatasource;
 
/**
 * mybatis配置
 * @author louis
 * @date oct 31, 2018
 */
@configuration
@mapperscan(basepackages = {"com.louis.**.dao"}) // 掃描dao
public class mybatisconfig {
 
 @bean("master")
 @primary
 @configurationproperties(prefix = "spring.datasource.master")
 public datasource master() {
  return datasourcebuilder.create().build();
 }
 
 @bean("slave")
 @configurationproperties(prefix = "spring.datasource.slave")
 public datasource slave() {
  return datasourcebuilder.create().build();
 }
 
 @bean("dynamicdatasource")
 public datasource dynamicdatasource() {
  dynamicdatasource dynamicdatasource = new dynamicdatasource();
  map<object, object> datasourcemap = new hashmap<>(2);
  datasourcemap.put("master", master());
  datasourcemap.put("slave", slave());
  // 將 master 數(shù)據(jù)源作為默認(rèn)指定的數(shù)據(jù)源
  dynamicdatasource.setdefaultdatasource(master());
  // 將 master 和 slave 數(shù)據(jù)源作為指定的數(shù)據(jù)源
  dynamicdatasource.setdatasources(datasourcemap);
  return dynamicdatasource;
 }
 
 @bean
 public sqlsessionfactorybean sqlsessionfactorybean() throws exception {
  sqlsessionfactorybean sessionfactory = new sqlsessionfactorybean();
  // 配置數(shù)據(jù)源,此處配置為關(guān)鍵配置,如果沒(méi)有將 dynamicdatasource作為數(shù)據(jù)源則不能實(shí)現(xiàn)切換
  sessionfactory.setdatasource(dynamicdatasource());
  sessionfactory.settypealiasespackage("com.louis.**.model"); // 掃描model
  pathmatchingresourcepatternresolver resolver = new pathmatchingresourcepatternresolver();
  sessionfactory.setmapperlocations(resolver.getresources("classpath*:**/sqlmap/*.xml")); // 掃描映射文件
  return sessionfactory;
 }
 
 @bean
 public platformtransactionmanager transactionmanager() {
  // 配置事務(wù)管理, 使用事務(wù)時(shí)在方法頭部添加@transactional注解即可
  return new datasourcetransactionmanager(dynamicdatasource());
 }
}

動(dòng)態(tài)數(shù)據(jù)源類(lèi)

我們上一步把這個(gè)動(dòng)態(tài)數(shù)據(jù)源設(shè)置到了sql會(huì)話工廠和事務(wù)管理器,這樣在操作數(shù)據(jù)庫(kù)時(shí)就會(huì)通過(guò)動(dòng)態(tài)數(shù)據(jù)源類(lèi)來(lái)獲取要操作的數(shù)據(jù)源了。

動(dòng)態(tài)數(shù)據(jù)源類(lèi)集成了spring提供的abstractroutingdatasource類(lèi),abstractroutingdatasource 中 獲取數(shù)據(jù)源的方法就是 determinetargetdatasource,而此方法又通過(guò) determinecurrentlookupkey 方法獲取查詢(xún)數(shù)據(jù)源的key。

所以如果我們需要?jiǎng)討B(tài)切換數(shù)據(jù)源,就可以通過(guò)以下兩種方式定制:

1. 覆寫(xiě) determinecurrentlookupkey 方法

通過(guò)覆寫(xiě) determinecurrentlookupkey 方法,從一個(gè)自定義的 dynamicdatasourcecontextholder.getdatasourcekey() 獲取數(shù)據(jù)源key值,這樣在我們想動(dòng)態(tài)切換數(shù)據(jù)源的時(shí)候,只要通過(guò)  dynamicdatasourcecontextholder.setdatasourcekey(key)  的方式就可以動(dòng)態(tài)改變數(shù)據(jù)源了。這種方式要求在獲取數(shù)據(jù)源之前,要先初始化各個(gè)數(shù)據(jù)源到 dynamicdatasource 中,我們案例就是采用這種方式實(shí)現(xiàn)的,所以在 mybatisconfig 中把master和slave數(shù)據(jù)源都事先初始化到dynamicdatasource 中。

2. 可以通過(guò)覆寫(xiě) determinetargetdatasource,因?yàn)閿?shù)據(jù)源就是在這個(gè)方法創(chuàng)建并返回的,所以這種方式就比較自由了,支持到任何你希望的地方讀取數(shù)據(jù)源信息,只要最終返回一個(gè) datasource 的實(shí)現(xiàn)類(lèi)即可。比如你可以到數(shù)據(jù)庫(kù)、本地文件、網(wǎng)絡(luò)接口等方式讀取到數(shù)據(jù)源信息然后返回相應(yīng)的數(shù)據(jù)源對(duì)象就可以了。

?
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
dynamicdatasource.java
 
package com.louis.springboot.dynamic.datasource.dds;
 
import java.util.map;
 
import javax.sql.datasource;
 
import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource;
 
/**
 * 動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)類(lèi)
 * @author louis
 * @date oct 31, 2018
 */
public class dynamicdatasource extends abstractroutingdatasource {
  
  
  /**
   * 如果不希望數(shù)據(jù)源在啟動(dòng)配置時(shí)就加載好,可以定制這個(gè)方法,從任何你希望的地方讀取并返回?cái)?shù)據(jù)源
   * 比如從數(shù)據(jù)庫(kù)、文件、外部接口等讀取數(shù)據(jù)源信息,并最終返回一個(gè)datasource實(shí)現(xiàn)類(lèi)對(duì)象即可
   */
  @override
  protected datasource determinetargetdatasource() {
    return super.determinetargetdatasource();
  }
  
  /**
   * 如果希望所有數(shù)據(jù)源在啟動(dòng)配置時(shí)就加載好,這里通過(guò)設(shè)置數(shù)據(jù)源key值來(lái)切換數(shù)據(jù),定制這個(gè)方法
   */
  @override
  protected object determinecurrentlookupkey() {
    return dynamicdatasourcecontextholder.getdatasourcekey();
  }
  
  /**
   * 設(shè)置默認(rèn)數(shù)據(jù)源
   * @param defaultdatasource
   */
  public void setdefaultdatasource(object defaultdatasource) {
    super.setdefaulttargetdatasource(defaultdatasource);
  }
  
  /**
   * 設(shè)置數(shù)據(jù)源
   * @param datasources
   */
  public void setdatasources(map<object, object> datasources) {
    super.settargetdatasources(datasources);
    // 將數(shù)據(jù)源的 key 放到數(shù)據(jù)源上下文的 key 集合中,用于切換時(shí)判斷數(shù)據(jù)源是否有效
    dynamicdatasourcecontextholder.adddatasourcekeys(datasources.keyset());
  }
}

數(shù)據(jù)源上下文

動(dòng)態(tài)數(shù)據(jù)源的切換主要是通過(guò)調(diào)用這個(gè)類(lèi)的方法來(lái)完成的。在任何想要進(jìn)行切換數(shù)據(jù)源的時(shí)候都可以通過(guò)調(diào)用這個(gè)類(lèi)的方法實(shí)現(xiàn)切換。比如系統(tǒng)登錄時(shí),根據(jù)用戶(hù)信息調(diào)用這個(gè)類(lèi)的數(shù)據(jù)源切換方法切換到用戶(hù)對(duì)應(yīng)的數(shù)據(jù)庫(kù)。

主要方法介紹:

1. 切換數(shù)據(jù)源

在任何想要進(jìn)行切換數(shù)據(jù)源的時(shí)候都可以通過(guò)調(diào)用這個(gè)類(lèi)的方法實(shí)現(xiàn)切換。

?
1
2
3
4
5
6
7
/**
 * 切換數(shù)據(jù)源
 * @param key
 */
public static void setdatasourcekey(string key) {
  contextholder.set(key);
}

2. 重置數(shù)據(jù)源

將數(shù)據(jù)源重置回默認(rèn)的數(shù)據(jù)源。默認(rèn)數(shù)據(jù)源通過(guò) dynamicdatasource.setdefaultdatasource(ds) 進(jìn)行設(shè)置。

?
1
2
3
4
5
6
/**
 * 重置數(shù)據(jù)源
 */
public static void cleardatasourcekey() {
  contextholder.remove();
}

3. 獲取當(dāng)前數(shù)據(jù)源key

?
1
2
3
4
5
6
7
/**
 * 獲取數(shù)據(jù)源
 * @return
 */
public static string getdatasourcekey() {
  return contextholder.get();
}

完整代碼如下

?
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
dynamicdatasourcecontextholder.java
 
package com.louis.springboot.dynamic.datasource.dds;
 
import java.util.arraylist;
import java.util.collection;
import java.util.list;
 
/**
 * 動(dòng)態(tài)數(shù)據(jù)源上下文
 * @author louis
 * @date oct 31, 2018
 */
public class dynamicdatasourcecontextholder {
 
  private static final threadlocal<string> contextholder = new threadlocal<string>() {
    /**
     * 將 master 數(shù)據(jù)源的 key作為默認(rèn)數(shù)據(jù)源的 key
     */
    @override
    protected string initialvalue() {
      return "master";
    }
  };
 
 
  /**
   * 數(shù)據(jù)源的 key集合,用于切換時(shí)判斷數(shù)據(jù)源是否存在
   */
  public static list<object> datasourcekeys = new arraylist<>();
 
  /**
   * 切換數(shù)據(jù)源
   * @param key
   */
  public static void setdatasourcekey(string key) {
    contextholder.set(key);
  }
 
  /**
   * 獲取數(shù)據(jù)源
   * @return
   */
  public static string getdatasourcekey() {
    return contextholder.get();
  }
 
  /**
   * 重置數(shù)據(jù)源
   */
  public static void cleardatasourcekey() {
    contextholder.remove();
  }
 
  /**
   * 判斷是否包含數(shù)據(jù)源
   * @param key 數(shù)據(jù)源key
   * @return
   */
  public static boolean containdatasourcekey(string key) {
    return datasourcekeys.contains(key);
  }
  
  /**
   * 添加數(shù)據(jù)源keys
   * @param keys
   * @return
   */
  public static boolean adddatasourcekeys(collection<? extends object> keys) {
    return datasourcekeys.addall(keys);
  }
}

注解式數(shù)據(jù)源

到這里,在任何想要?jiǎng)討B(tài)切換數(shù)據(jù)源的時(shí)候,只要調(diào)用  dynamicdatasourcecontextholder.setdatasourcekey(key)  就可以完成了。

接下來(lái)我們實(shí)現(xiàn)通過(guò)注解的方式來(lái)進(jìn)行數(shù)據(jù)源的切換,原理就是添加注解(如@datasource(value="master")),然后實(shí)現(xiàn)注解切面進(jìn)行數(shù)據(jù)源切換。

創(chuàng)建一個(gè)動(dòng)態(tài)數(shù)據(jù)源注解,擁有一個(gè)value值,用于標(biāo)識(shí)要切換的數(shù)據(jù)源的key。

?
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
datasource.java
 
package com.louis.springboot.dynamic.datasource.dds;
 
import java.lang.annotation.documented;
import java.lang.annotation.elementtype;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
import java.lang.annotation.target;
 
/**
 * 動(dòng)態(tài)數(shù)據(jù)源注解
 * @author louis
 * @date oct 31, 2018
 */
@target({elementtype.method, elementtype.type})
@retention(retentionpolicy.runtime)
@documented
public @interface datasource {
  
  /**
   * 數(shù)據(jù)源key值
   * @return
   */
  string value();
  
}

創(chuàng)建一個(gè)aop切面,攔截帶 @datasource 注解的方法,在方法執(zhí)行前切換至目標(biāo)數(shù)據(jù)源,執(zhí)行完成后恢復(fù)到默認(rèn)數(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
dynamicdatasourceaspect.java
 
package com.louis.springboot.dynamic.datasource.dds;
 
import org.aspectj.lang.joinpoint;
import org.aspectj.lang.annotation.after;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.before;
import org.springframework.core.annotation.order;
import org.springframework.stereotype.component;
 
/**
 * 動(dòng)態(tài)數(shù)據(jù)源切換處理器
 * @author louis
 * @date oct 31, 2018
 */
@aspect
@order(-1) // 該切面應(yīng)當(dāng)先于 @transactional 執(zhí)行
@component
public class dynamicdatasourceaspect {
  
  /**
   * 切換數(shù)據(jù)源
   * @param point
   * @param datasource
   */
  @before("@annotation(datasource))")
  public void switchdatasource(joinpoint point, datasource datasource) {
    if (!dynamicdatasourcecontextholder.containdatasourcekey(datasource.value())) {
      system.out.println("datasource [{}] doesn't exist, use default datasource [{}] " + datasource.value());
    } else {
      // 切換數(shù)據(jù)源
      dynamicdatasourcecontextholder.setdatasourcekey(datasource.value());
      system.out.println("switch datasource to [" + dynamicdatasourcecontextholder.getdatasourcekey()
        + "] in method [" + point.getsignature() + "]");
    }
  }
 
  /**
   * 重置數(shù)據(jù)源
   * @param point
   * @param datasource
   */
  @after("@annotation(datasource))")
  public void restoredatasource(joinpoint point, datasource datasource) {
    // 將數(shù)據(jù)源置為默認(rèn)數(shù)據(jù)源
    dynamicdatasourcecontextholder.cleardatasourcekey();
    system.out.println("restore datasource to [" + dynamicdatasourcecontextholder.getdatasourcekey()
      + "] in method [" + point.getsignature() + "]");
  }
}

到這里,動(dòng)態(tài)數(shù)據(jù)源相關(guān)的處理代碼就完成了。

編寫(xiě)用戶(hù)業(yè)務(wù)代碼

接下來(lái)編寫(xiě)用戶(hù)查詢(xún)業(yè)務(wù)代碼,用來(lái)進(jìn)行測(cè)試,只需添加一個(gè)查詢(xún)接口即可。

編寫(xiě)一個(gè)控制器,包含兩個(gè)查詢(xún)方法,分別注解 master 和 slave 數(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
sysusercontroller.java
package com.louis.springboot.dynamic.datasource.controller;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;
import com.louis.springboot.dynamic.datasource.dds.datasource;
import com.louis.springboot.dynamic.datasource.service.sysuserservice;
/**
 * 用戶(hù)控制器
 * @author louis
 * @date oct 31, 2018
 */
@restcontroller
@requestmapping("user")
public class sysusercontroller {
  @autowired
  private sysuserservice sysuserservice;
  @datasource(value="master")
  @postmapping(value="/findall")
  public object findall() {
    return sysuserservice.findall();
  }
  @datasource(value="slave")
  @postmapping(value="/findall2")
  public object findall2() {
    return sysuserservice.findall();
  }
}

下面是正常的業(yè)務(wù)代碼,沒(méi)有什么好說(shuō)明的,直接貼代碼了。

?
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
sysuser.java
public class sysuser {
  private long id;
  private string name;
  private string password;
  private string salt;
  private string email;
  private string mobile;
  private byte status;
  private long deptid;
  private string deptname;
  private byte delflag;
  private string createby;
  private date createtime;
  private string lastupdateby;
  private date lastupdatetime;
  ...setter and getter
}
sysusermapper.java
package com.louis.springboot.dynamic.datasource.dao;
import java.util.list;
import com.louis.springboot.dynamic.datasource.model.sysuser;
public interface sysusermapper {
  int deletebyprimarykey(long id);
  int insert(sysuser record);
  int insertselective(sysuser record);
  sysuser selectbyprimarykey(long id);
  int updatebyprimarykeyselective(sysuser record);
  int updatebyprimarykey(sysuser record);
  list<sysuser> findall();
}

sysusermapper.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<?xml version="1.0" encoding="utf-8"?>
<!doctype mapper public "-//mybatis.org//dtd mapper 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.louis.springboot.dynamic.datasource.dao.sysusermapper">
 <resultmap id="baseresultmap" type="com.louis.springboot.dynamic.datasource.model.sysuser">
  <id column="id" jdbctype="bigint" property="id" />
  <result column="name" jdbctype="varchar" property="name" />
  <result column="password" jdbctype="varchar" property="password" />
  <result column="salt" jdbctype="varchar" property="salt" />
  <result column="email" jdbctype="varchar" property="email" />
  <result column="mobile" jdbctype="varchar" property="mobile" />
  <result column="status" jdbctype="tinyint" property="status" />
  <result column="dept_id" jdbctype="bigint" property="deptid" />
  <result column="create_by" jdbctype="bigint" property="createby" />
  <result column="create_time" jdbctype="timestamp" property="createtime" />
  <result column="last_update_by" jdbctype="bigint" property="lastupdateby" />
  <result column="last_update_time" jdbctype="timestamp" property="lastupdatetime" />
  <result column="del_flag" jdbctype="tinyint" property="delflag" />
 </resultmap>
 <sql id="base_column_list">
  id, name, password, salt, email, mobile, status, dept_id, create_by, create_time,
  last_update_by, last_update_time, del_flag
 </sql>
 <select id="selectbyprimarykey" parametertype="java.lang.long" resultmap="baseresultmap">
  select
  <include refid="base_column_list" />
  from sys_user
  where id = #{id,jdbctype=bigint}
 </select>
 <delete id="deletebyprimarykey" parametertype="java.lang.long">
  delete from sys_user
  where id = #{id,jdbctype=bigint}
 </delete>
 <insert id="insert" parametertype="com.louis.springboot.dynamic.datasource.model.sysuser">
  insert into sys_user (id, name, password,
   salt, email, mobile,
   status, dept_id, create_by,
   create_time, last_update_by, last_update_time,
   del_flag)
  values (#{id,jdbctype=bigint}, #{name,jdbctype=varchar}, #{password,jdbctype=varchar},
   #{salt,jdbctype=varchar}, #{email,jdbctype=varchar}, #{mobile,jdbctype=varchar},
   #{status,jdbctype=tinyint}, #{deptid,jdbctype=bigint}, #{createby,jdbctype=bigint},
   #{createtime,jdbctype=timestamp}, #{lastupdateby,jdbctype=bigint}, #{lastupdatetime,jdbctype=timestamp},
   #{delflag,jdbctype=tinyint})
 </insert>
 <insert id="insertselective" parametertype="com.louis.springboot.dynamic.datasource.model.sysuser">
  insert into sys_user
  <trim prefix="(" suffix=")" suffixoverrides=",">
   <if test="id != null">
    id,
   </if>
   <if test="name != null">
    name,
   </if>
   <if test="password != null">
    password,
   </if>
   <if test="salt != null">
    salt,
   </if>
   <if test="email != null">
    email,
   </if>
   <if test="mobile != null">
    mobile,
   </if>
   <if test="status != null">
    status,
   </if>
   <if test="deptid != null">
    dept_id,
   </if>
   <if test="createby != null">
    create_by,
   </if>
   <if test="createtime != null">
    create_time,
   </if>
   <if test="lastupdateby != null">
    last_update_by,
   </if>
   <if test="lastupdatetime != null">
    last_update_time,
   </if>
   <if test="delflag != null">
    del_flag,
   </if>
  </trim>
  <trim prefix="values (" suffix=")" suffixoverrides=",">
   <if test="id != null">
    #{id,jdbctype=bigint},
   </if>
   <if test="name != null">
    #{name,jdbctype=varchar},
   </if>
   <if test="password != null">
    #{password,jdbctype=varchar},
   </if>
   <if test="salt != null">
    #{salt,jdbctype=varchar},
   </if>
   <if test="email != null">
    #{email,jdbctype=varchar},
   </if>
   <if test="mobile != null">
    #{mobile,jdbctype=varchar},
   </if>
   <if test="status != null">
    #{status,jdbctype=tinyint},
   </if>
   <if test="deptid != null">
    #{deptid,jdbctype=bigint},
   </if>
   <if test="createby != null">
    #{createby,jdbctype=bigint},
   </if>
   <if test="createtime != null">
    #{createtime,jdbctype=timestamp},
   </if>
   <if test="lastupdateby != null">
    #{lastupdateby,jdbctype=bigint},
   </if>
   <if test="lastupdatetime != null">
    #{lastupdatetime,jdbctype=timestamp},
   </if>
   <if test="delflag != null">
    #{delflag,jdbctype=tinyint},
   </if>
  </trim>
 </insert>
 <update id="updatebyprimarykeyselective" parametertype="com.louis.springboot.dynamic.datasource.model.sysuser">
  update sys_user
  <set>
   <if test="name != null">
    name = #{name,jdbctype=varchar},
   </if>
   <if test="password != null">
    password = #{password,jdbctype=varchar},
   </if>
   <if test="salt != null">
    salt = #{salt,jdbctype=varchar},
   </if>
   <if test="email != null">
    email = #{email,jdbctype=varchar},
   </if>
   <if test="mobile != null">
    mobile = #{mobile,jdbctype=varchar},
   </if>
   <if test="status != null">
    status = #{status,jdbctype=tinyint},
   </if>
   <if test="deptid != null">
    dept_id = #{deptid,jdbctype=bigint},
   </if>
   <if test="createby != null">
    create_by = #{createby,jdbctype=bigint},
   </if>
   <if test="createtime != null">
    create_time = #{createtime,jdbctype=timestamp},
   </if>
   <if test="lastupdateby != null">
    last_update_by = #{lastupdateby,jdbctype=bigint},
   </if>
   <if test="lastupdatetime != null">
    last_update_time = #{lastupdatetime,jdbctype=timestamp},
   </if>
   <if test="delflag != null">
    del_flag = #{delflag,jdbctype=tinyint},
   </if>
  </set>
  where id = #{id,jdbctype=bigint}
 </update>
 <update id="updatebyprimarykey" parametertype="com.louis.springboot.dynamic.datasource.model.sysuser">
  update sys_user
  set name = #{name,jdbctype=varchar},
   password = #{password,jdbctype=varchar},
   salt = #{salt,jdbctype=varchar},
   email = #{email,jdbctype=varchar},
   mobile = #{mobile,jdbctype=varchar},
   status = #{status,jdbctype=tinyint},
   dept_id = #{deptid,jdbctype=bigint},
   create_by = #{createby,jdbctype=bigint},
   create_time = #{createtime,jdbctype=timestamp},
   last_update_by = #{lastupdateby,jdbctype=bigint},
   last_update_time = #{lastupdatetime,jdbctype=timestamp},
   del_flag = #{delflag,jdbctype=tinyint}
  where id = #{id,jdbctype=bigint}
 </update>
 <select id="findall" resultmap="baseresultmap">
  select
  <include refid="base_column_list" />
  from sys_user
 </select>
</mapper>

sysuserservice.java

?
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
package com.louis.springboot.dynamic.datasource.service;
import java.util.list;
import com.louis.springboot.dynamic.datasource.model.sysuser;
/**
 * 用戶(hù)管理
 * @author louis
 * @date oct 31, 2018
 */
public interface sysuserservice {
  /**
   * 查找全部用戶(hù)信息
   * @return
   */
  list<sysuser> findall();
}
sysuserserviceimpl.java
package com.louis.springboot.dynamic.datasource.service.impl;
import java.util.list;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.service;
import com.louis.springboot.dynamic.datasource.dao.sysusermapper;
import com.louis.springboot.dynamic.datasource.model.sysuser;
import com.louis.springboot.dynamic.datasource.service.sysuserservice;
@service
public class sysuserserviceimpl implements sysuserservice {
  @autowired
  private sysusermapper sysusermapper;
  /**
   * 查找全部用戶(hù)信息
   * @return
   */
  public list<sysuser> findall() {
    return sysusermapper.findall();
  }
}

測(cè)試效果

啟動(dòng)系統(tǒng),訪問(wèn)   http://localhost:8080/swagger-ui.html ,分別測(cè)試兩個(gè)接口,成功返回?cái)?shù)據(jù)。

user/findall (master數(shù)據(jù)源)

 Spring Boot + Mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源案例分析

user/findall2 (slave數(shù)據(jù)源)

Spring Boot + Mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源案例分析

源碼下載

碼云:https://gitee.com/liuge1988/spring-boot-demo.git

總結(jié)

以上所述是小編給大家介紹的spring boot + mybatis 實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源案例分析,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)服務(wù)器之家網(wǎng)站的支持!

原文鏈接:http://www.cnblogs.com/xifengxiaoma/p/9888240.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: chinesegay黑袜玩奴 | 短篇最污的乱淫伦小说全集 | 午夜神器老司机高清无码 | 成人午夜毛片 | 亚飞与亚基高清国语在线观看 | 欧美不卡一区二区三区 | 日处女b| 91制片厂 果冻传媒 天美传媒 | 亚洲品质自拍视频网站 | 无码乱人伦一区二区亚洲 | 亚洲第一综合天堂另类专 | 午夜秀场在线观看 | 5g影院天天 | 日本漫画工囗全彩番在线 | 国产清纯91天堂在线观看 | 视频一区二区国产无限在线观看 | 爱草视频 | 成人网免费视频 | 欧美日韩一区二区综合 | 美女牲交毛片一级视频 | 亚洲精品91大神在线观看 | 色呦呦在线免费观看 | youwu在线影院 | 国产123区在线视频观看 | 黄色wwwwww| 四虎免费影院4hu永久免费 | 色综合久久久 | 美女被草逼| 国产四虎| 欧美日韩国产精品va | 美女天天操 | xxxxxx日本处大片免费看 | 王雨纯 羞羞 | 午夜在线观看免费完整直播网 | kkkk4444在线看片免费 | 国产精品免费综合一区视频 | 亚洲国产精品自在现线让你爽 | 久久综合网久久综合 | 91在线一区二区三区 | 国产乱妇无码大片在线观看 | 青青青在线观看国产精品 |