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

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

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

服務器之家 - 編程語言 - Java教程 - 詳解Spring Boot + Mybatis 實現動態數據源

詳解Spring Boot + Mybatis 實現動態數據源

2021-08-01 11:50Boblim Java教程

這篇文章主要介紹了Spring Boot + Mybatis 實現動態數據源,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

動態數據源

在很多具體應用場景的時候,我們需要用到動態數據源的情況,比如多租戶的場景,系統登錄時需要根據用戶信息切換到用戶對應的數據庫。又比如業務a要訪問a數據庫,業務b要訪問b數據庫等,都可以使用動態數據源方案進行解決。接下來,我們就來講解如何實現動態數據源,以及在過程中剖析動態數據源背后的實現原理。

實現案例

本教程案例基于 spring boot + mybatis + mysql 實現。

數據庫設計

首先需要安裝好mysql數據庫,新建數據庫 example,創建example表,用來測試數據源,sql腳本如下:

?
1
2
3
4
5
6
7
create table `example` (
 `pk` bigint(20) unsigned not null auto_increment comment '主鍵',
 `message` varchar(100) not null,
 `create_time` datetime not null comment '創建時間',
 `modify_time` datetime default null comment '生效時間',
 primary key (`pk`)
) engine=innodb auto_increment=2 default charset=utf8 row_format=compact comment='測試用例表'

添加依賴

添加spring boot,spring aop,mybatis,mysql相關依賴。

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
<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>
  <dependency>
   <groupid>org.mybatis.spring.boot</groupid>
   <artifactid>mybatis-spring-boot-starter</artifactid>
   <version>1.3.1</version>
  </dependency>
  <!-- spring aop -->
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-aop</artifactid>
  </dependency>
  <dependency>
   <groupid>mysql</groupid>
   <artifactid>mysql-connector-java</artifactid>
   <version>5.1.8</version>
  </dependency>

自定義配置文件

新建自定義配置文件resource/config/mysql/db.properties,添加數據源:

?
1
2
3
4
5
#數據庫設置
spring.datasource.example.jdbc-url=jdbc:mysql://localhost:3306/example?characterencoding=utf-8
spring.datasource.example.username=root
spring.datasource.example.password=123456
spring.datasource.example.driver-class-name=com.mysql.jdbc.driver

啟動類

啟動類添加 exclude = {datasourceautoconfiguration.class}, 以禁用數據源默認自動配置。

數據源默認自動配置會讀取 spring.datasource.* 的屬性創建數據源,所以要禁用以進行定制。

dynamicdatasourceapplication.java:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.main.example.dynamic.datasource;
 
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.boot.autoconfigure.jdbc.datasourceautoconfiguration;
 
@springbootapplication(exclude = {
    datasourceautoconfiguration.class
})
public class dynamicdatasourceapplication {
 
 public static void main(string[] args) {
  springapplication.run(dynamicdatasourceapplication.class, args);
 }
 
}

數據源配置類

創建一個數據源配置類,主要做以下幾件事情:

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

2. 注入數據源配置屬性,創建數據源。

3. 創建一個動態數據源,裝入數據源。

4. 將動態數據源設置到sql會話工廠和事務管理器。

如此,當進行數據庫操作時,就會通過我們創建的動態數據源去獲取要操作的數據源了。

dbsourceconfig.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
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.main.example.config.dao;
 
import com.main.example.common.dataenum;
import com.main.example.common.dynamicdatasource;
import org.mybatis.spring.sqlsessionfactorybean;
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.propertysource;
import org.springframework.core.io.support.pathmatchingresourcepatternresolver;
import org.springframework.jdbc.datasource.datasourcetransactionmanager;
import org.springframework.transaction.platformtransactionmanager;
 
import javax.sql.datasource;
import java.util.hashmap;
import java.util.map;
 
//數據庫配置統一在config/mysql/db.properties中
@configuration
@propertysource(value = "classpath:config/mysql/db.properties")
public class dbsourceconfig {
  private string typealiasespackage = "com.main.example.bean.**.*";
 
  @bean(name = "exampledatasource")
  @configurationproperties(prefix = "spring.datasource.example")
  public datasource exampledatasource() {
    return datasourcebuilder.create().build();
  }
 
  /*
   * 動態數據源
   * dbmap中存放數據源名稱與數據源實例,數據源名稱存于dataenum.dbsource中
   * setdefaulttargetdatasource方法設置默認數據源
   */
  @bean(name = "dynamicdatasource")
  public datasource dynamicdatasource() {
    dynamicdatasource dynamicdatasource = new dynamicdatasource();
    //配置多數據源
    map<object, object> dbmap = new hashmap();
    dbmap.put(dataenum.dbsource.example.getname(), exampledatasource());
    dynamicdatasource.settargetdatasources(dbmap);
 
    // 設置默認數據源
    dynamicdatasource.setdefaulttargetdatasource(exampledatasource());
 
    return dynamicdatasource;
  }
 
  /*
   * 數據庫連接會話工廠
   * 將動態數據源賦給工廠
   * mapper存于resources/mapper目錄下
   * 默認bean存于com.main.example.bean包或子包下,也可直接在mapper中指定
   */
  @bean(name = "sqlsessionfactory")
  public sqlsessionfactorybean sqlsessionfactory() throws exception {
    sqlsessionfactorybean sqlsessionfactory = new sqlsessionfactorybean();
    sqlsessionfactory.setdatasource(dynamicdatasource());
    sqlsessionfactory.settypealiasespackage(typealiasespackage); //掃描bean
    pathmatchingresourcepatternresolver resolver = new pathmatchingresourcepatternresolver();
    sqlsessionfactory.setmapperlocations(resolver.getresources("classpath*:mapper/*.xml"));  // 掃描映射文件
 
    return sqlsessionfactory;
  }
 
  @bean
  public platformtransactionmanager transactionmanager() {
    // 配置事務管理, 使用事務時在方法頭部添加@transactional注解即可
    return new datasourcetransactionmanager(dynamicdatasource());
  }
}

動態數據源類

我們上一步把這個動態數據源設置到了sql會話工廠和事務管理器,這樣在操作數據庫時就會通過動態數據源類來獲取要操作的數據源了。

動態數據源類集成了spring提供的abstractroutingdatasource類,abstractroutingdatasource 中獲取數據源的方法就是 determinetargetdatasource,而此方法又通過 determinecurrentlookupkey 方法獲取查詢數據源的key。

所以如果我們需要動態切換數據源,就可以通過以下兩種方式定制:

1. 覆寫 determinecurrentlookupkey 方法

通過覆寫 determinecurrentlookupkey 方法,從一個自定義的 dbsourcecontext.getdbsource() 獲取數據源key值,這樣在我們想動態切換數據源的時候,只要通過  dbsourcecontext.setdbsource(key)  的方式就可以動態改變數據源了。這種方式要求在獲取數據源之前,要先初始化各個數據源到 dbsourcecontext 中,我們案例就是采用這種方式實現的,所以要將數據源都事先初始化到dynamicdatasource 中。

2. 可以通過覆寫 determinetargetdatasource,因為數據源就是在這個方法創建并返回的,所以這種方式就比較自由了,支持到任何你希望的地方讀取數據源信息,只要最終返回一個 datasource 的實現類即可。比如你可以到數據庫、本地文件、網絡接口等方式讀取到數據源信息然后返回相應的數據源對象就可以了。

dynamicdatasource.java:

?
1
2
3
4
5
6
7
8
9
10
11
12
package com.main.example.common;
 
import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource;
 
public class dynamicdatasource extends abstractroutingdatasource {
 
  @override
  protected object determinecurrentlookupkey() {
    return dbsourcecontext.getdbsource();
  }
 
}

數據源上下文

動態數據源的切換主要是通過調用這個類的方法來完成的。在任何想要進行切換數據源的時候都可以通過調用這個類的方法實現切換。比如系統登錄時,根據用戶信息調用這個類的數據源切換方法切換到用戶對應的數據庫。完整代碼如下:

dbsourcecontext.java:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.main.example.common;
 
import org.apache.log4j.logger;
 
public class dbsourcecontext {
  private static logger logger = logger.getlogger(dbsourcecontext.class);
 
  private static final threadlocal<string> dbcontext = new threadlocal<string>();
 
  public static void setdbsource(string source) {
    logger.debug("set source ====>" + source);
    dbcontext.set(source);
  }
 
  public static string getdbsource() {
    logger.debug("get source ====>" + dbcontext.get());
    return dbcontext.get();
  }
 
  public static void cleardbsource() {
    dbcontext.remove();
  }
}

注解式數據源

到這里,在任何想要動態切換數據源的時候,只要調用dbsourcecontext.setdbsource(key)  就可以完成了。

接下來我們實現通過注解的方式來進行數據源的切換,原理就是添加注解(如@dbsource(value="example")),然后實現注解切面進行數據源切換。

創建一個動態數據源注解,擁有一個value值,用于標識要切換的數據源的key。

dbsource.java:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.main.example.config.dao;
 
import java.lang.annotation.*;
 
/**
 * 動態數據源注解
 * @author
 * @date april 12, 2019
 */
@target({elementtype.method, elementtype.type})
@retention(retentionpolicy.runtime)
@documented
public @interface dbsource {
  /**
   * 數據源key值
   * @return
   */
  string value();
}

創建一個aop切面,攔截帶 @datasource 注解的方法,在方法執行前切換至目標數據源,執行完成后恢復到默認數據源。

dynamicdatasourceaspect.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
36
37
38
39
40
41
42
43
44
45
46
package com.main.example.config.dao;
 
import com.main.example.common.dbsourcecontext;
import org.apache.log4j.logger;
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;
 
/**
 * 動態數據源切換處理器
 * @author linzhibao
 * @date april 12, 2019
 */
@aspect
@order(-1) // 該切面應當先于 @transactional 執行
@component
public class dynamicdatasourceaspect {
  private static logger logger = logger.getlogger(dynamicdatasourceaspect.class);
  /**
   * 切換數據源
   * @param point
   * @param dbsource
   */
  //@before("@annotation(dbsource)") 注解在對應方法,攔截有@dbsource的方法
  //注解在類對象,攔截有@dbsource類下所有的方法
  @before("@within(dbsource)")
  public void switchdatasource(joinpoint point, dbsource dbsource) {
      // 切換數據源
      dbsourcecontext.setdbsource(dbsource.value());
  }
 
  /**
   * 重置數據源
   * @param point
   * @param dbsource
   */
  //注解在類對象,攔截有@dbsource類下所有的方法
  @after("@within(dbsource)")
  public void restoredatasource(joinpoint point, dbsource dbsource) {
    // 將數據源置為默認數據源
    dbsourcecontext.cleardbsource();
  }
}

到這里,動態數據源相關的處理代碼就完成了。

編寫用戶業務代碼

接下來編寫用戶查詢業務代碼,用來進行測試,dao層只需添加一個查詢接口即可。

exampledao.java:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.main.example.dao;
 
import com.main.example.common.dataenum;
import com.main.example.config.dao.dbsource;
import org.springframework.context.annotation.bean;
import org.springframework.stereotype.component;
 
import javax.annotation.resource;
import java.util.list;
 
@component("exampledao")
//切換數據源注解,以dataenum.dbsource中的值為準
@dbsource("example")
public class exampledao extends daobase {
  private static final string mapper_name_space = "com.main.example.dao.examplemapper";
 
  public list<string> selectallmessages() {
    return selectlist(mapper_name_space, "selectallmessages");
  }
}

controler代碼:

testexampledao.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
package com.main.example.dao;
 
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.restcontroller;
 
import java.util.arraylist;
import java.util.list;
 
@restcontroller
public class testexampledao {
  @autowired
  exampledao exampledao;
 
  @requestmapping(value = "/test/example")
  public list<string> selectallmessages() {
    try {
      list<string> ldata = exampledao.selectallmessages();
      if(ldata == null){system.out.println("*********it is null.***********");return null;}
      for(string d : ldata) {
        system.out.println(d);
      }
      return ldata;
    }catch(exception e) {
      e.printstacktrace();
    }
 
    return new arraylist<>();
  }
}

examplemapper.xml代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
<?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.main.example.dao.examplemapper">
  <select id="selectallmessages" resulttype="java.lang.string">
    select
    message
    from example
  </select>
 
</mapper>

測試效果

啟動系統,訪問 http://localhost:80/test/example">http://localhost:80/test/example,分別測試兩個接口,成功返回數據。

 詳解Spring Boot + Mybatis 實現動態數據源

可能遇到的問題

1.報錯:java.lang.illegalargumentexception: jdbcurl is required with driverclassname

 詳解Spring Boot + Mybatis 實現動態數據源

原因:

spring boot從1.x升級到2.x版本之后,一些配置及用法有了變化,如果不小心就會碰到“jdbcurl is required with driverclassname.”的錯誤

解決方法:

在1.0 配置數據源的過程中主要是寫成:spring.datasource.url 和spring.datasource.driverclassname。

而在2.0升級之后需要變更成:spring.datasource.jdbc-url和spring.datasource.driver-class-name即可解決!

 2.自定義配置文件

自定義配置文件需要在指定配置類上加上@propertysource標簽,例如:

?
1
@propertysource(value = "classpath:config/mysql/db.properties")

若是作用于配置類中的方法,則在方法上加上@configurationproperties,例如:

?
1
@configurationproperties(prefix = "spring.datasource.example")

配置項前綴為spring.datasource.example

若是作用于配置類上,則在類上加上@configurationproperties(同上),并且在啟動類上加上@enableconfigurationproperties(xxx.class)

3.多數據源

需要在啟動類上取消自動裝載數據源,如:

?
1
2
3
@springbootapplication(exclude = {
    datasourceautoconfiguration.class
})

以上所述是小編給大家介紹的spring boot + mybatis 實現動態數據源詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:https://www.cnblogs.com/fnlingnzb-learner/p/10710145.html#top

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品在线免费观看视频 | chinese男性厕所撒尿合集 | 女张腿男人桶羞羞漫画 | 日韩免费在线看 | 国产色综合久久五月色婷婷中文 | 成年人免费观看 | chinese老太grandma | 性姿势女人嗷嗷叫图片 | 精品久久久久久久国产潘金莲 | 无人区在线观看免费国语完整版 | 美女被爆| 国产日产在线观看 | 青青草一区二区免费精品 | chinese帅男gayvideo| 毛片网在线观看 | 国产成人精品一区二区 | 日本一道高清不卡免费 | 天天干夜夜玩 | 国产亚洲女在线线精品 | 放荡女小洁的性日记 | 日本又黄又裸一级大黄裸片 | 国产三级精品三级男人的天堂 | 欧美日韩亚洲综合久久久 | 男人把大ji巴放进男人免费视频 | gogo人体模特啪啪季玥图片 | 色就色综合 | 色综合天天网 | 亚欧成人一区二区 | 超鹏97国语 | 美女用手扒开粉嫩的屁股 | 国产成人精品在线 | 范冰冰性xxxxhd | 好看的亚洲视频 | 国产成人h综合亚洲欧美在线 | 99视频九九精品视频在线观看 | 国产精品99精品久久免费 | 亚洲国产欧美在线看片 | 日本无翼乌漫画 | 亚洲狠狠网站色噜噜 | 猫咪社区免费资源在线观看 | 花核调教|