激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

服務(wù)器之家 - 編程語言 - Java教程 - 詳解Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源

詳解Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源

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

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

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

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

實現(xiàn)案例

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

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

首先需要安裝好mysql數(shù)據(jù)庫,新建數(shù)據(jù)庫 example,創(chuàng)建example表,用來測試數(shù)據(jù)源,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 '創(chuàng)建時間',
 `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相關(guān)依賴。

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,添加數(shù)據(jù)源:

?
1
2
3
4
5
#數(shù)據(jù)庫設(shè)置
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}, 以禁用數(shù)據(jù)源默認(rèn)自動配置。

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

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

數(shù)據(jù)源配置類

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

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

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

3. 創(chuàng)建一個動態(tài)數(shù)據(jù)源,裝入數(shù)據(jù)源。

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

如此,當(dāng)進(jìn)行數(shù)據(jù)庫操作時,就會通過我們創(chuàng)建的動態(tài)數(shù)據(jù)源去獲取要操作的數(shù)據(jù)源了。

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;
 
//數(shù)據(jù)庫配置統(tǒng)一在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();
  }
 
  /*
   * 動態(tài)數(shù)據(jù)源
   * dbmap中存放數(shù)據(jù)源名稱與數(shù)據(jù)源實例,數(shù)據(jù)源名稱存于dataenum.dbsource中
   * setdefaulttargetdatasource方法設(shè)置默認(rèn)數(shù)據(jù)源
   */
  @bean(name = "dynamicdatasource")
  public datasource dynamicdatasource() {
    dynamicdatasource dynamicdatasource = new dynamicdatasource();
    //配置多數(shù)據(jù)源
    map<object, object> dbmap = new hashmap();
    dbmap.put(dataenum.dbsource.example.getname(), exampledatasource());
    dynamicdatasource.settargetdatasources(dbmap);
 
    // 設(shè)置默認(rèn)數(shù)據(jù)源
    dynamicdatasource.setdefaulttargetdatasource(exampledatasource());
 
    return dynamicdatasource;
  }
 
  /*
   * 數(shù)據(jù)庫連接會話工廠
   * 將動態(tài)數(shù)據(jù)源賦給工廠
   * mapper存于resources/mapper目錄下
   * 默認(rèn)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() {
    // 配置事務(wù)管理, 使用事務(wù)時在方法頭部添加@transactional注解即可
    return new datasourcetransactionmanager(dynamicdatasource());
  }
}

動態(tài)數(shù)據(jù)源類

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

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

所以如果我們需要動態(tài)切換數(shù)據(jù)源,就可以通過以下兩種方式定制:

1. 覆寫 determinecurrentlookupkey 方法

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

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

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

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

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

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

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

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

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

創(chuàng)建一個動態(tài)數(shù)據(jù)源注解,擁有一個value值,用于標(biāo)識要切換的數(shù)據(jù)源的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.*;
 
/**
 * 動態(tài)數(shù)據(jù)源注解
 * @author
 * @date april 12, 2019
 */
@target({elementtype.method, elementtype.type})
@retention(retentionpolicy.runtime)
@documented
public @interface dbsource {
  /**
   * 數(shù)據(jù)源key值
   * @return
   */
  string value();
}

創(chuàng)建一個aop切面,攔截帶 @datasource 注解的方法,在方法執(zhí)行前切換至目標(biāo)數(shù)據(jù)源,執(zhí)行完成后恢復(fù)到默認(rèn)數(shù)據(jù)源。

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;
 
/**
 * 動態(tài)數(shù)據(jù)源切換處理器
 * @author linzhibao
 * @date april 12, 2019
 */
@aspect
@order(-1) // 該切面應(yīng)當(dāng)先于 @transactional 執(zhí)行
@component
public class dynamicdatasourceaspect {
  private static logger logger = logger.getlogger(dynamicdatasourceaspect.class);
  /**
   * 切換數(shù)據(jù)源
   * @param point
   * @param dbsource
   */
  //@before("@annotation(dbsource)") 注解在對應(yīng)方法,攔截有@dbsource的方法
  //注解在類對象,攔截有@dbsource類下所有的方法
  @before("@within(dbsource)")
  public void switchdatasource(joinpoint point, dbsource dbsource) {
      // 切換數(shù)據(jù)源
      dbsourcecontext.setdbsource(dbsource.value());
  }
 
  /**
   * 重置數(shù)據(jù)源
   * @param point
   * @param dbsource
   */
  //注解在類對象,攔截有@dbsource類下所有的方法
  @after("@within(dbsource)")
  public void restoredatasource(joinpoint point, dbsource dbsource) {
    // 將數(shù)據(jù)源置為默認(rèn)數(shù)據(jù)源
    dbsourcecontext.cleardbsource();
  }
}

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

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

接下來編寫用戶查詢業(yè)務(wù)代碼,用來進(jìn)行測試,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")
//切換數(shù)據(jù)源注解,以dataenum.dbsource中的值為準(zhǔn)
@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>

測試效果

啟動系統(tǒng),訪問 http://localhost:80/test/example">http://localhost:80/test/example,分別測試兩個接口,成功返回數(shù)據(jù)。

 詳解Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源

可能遇到的問題

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

 詳解Spring Boot + Mybatis 實現(xiàn)動態(tài)數(shù)據(jù)源

原因:

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

解決方法:

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

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

 2.自定義配置文件

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

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

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

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

配置項前綴為spring.datasource.example

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

3.多數(shù)據(jù)源

需要在啟動類上取消自動裝載數(shù)據(jù)源,如:

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

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 中文字幕专区高清在线观看 | 一级毛片一区 | h色视频在线观看 | 黄在线免费看 | 欧美高清第一页 | 羞羞视频免费入口网站 | 二区三区在线观看 | 综合网天天色 | 久久久精品视 | 国产精品久久久久久久久久三级 | 免费在线成人网 | 国产精品性夜天天视频 | 天天草天天爱 | 日韩精品免费一区二区三区 | 久久精品国产99国产精品澳门 | 国内精品伊人久久久久网站 | 美女扒开腿让男生桶爽网站 | 欧美一级特黄a | 天天透天天狠天天爱综合97 | 叶子楣成人爽a毛片免费啪啪 | 日本精品久久久久久草草 | 欧美日韩一区三区 | 色阁阁69婷婷 | 成人一级视频在线观看 | 欧美亚洲一区二区三区四区 | 成年人免费高清视频 | 一级在线观看视频 | 国产精品69页 | 91专区在线观看 | 欧美一级黄色片免费观看 | 在线视频观看一区二区 | aa国产视频一区二区 | 羞羞视频.www在线观看 | 亚洲一区二区网址 | 黄视频在线网站 | 看片91| 国产一区视频免费观看 | 免费成人| 蜜桃精品视频在线观看 | 免费一级特黄毛片视频 | 骚av在线 |