欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot多數(shù)據(jù)源配置并通過注解實(shí)現(xiàn)動態(tài)切換數(shù)據(jù)源

 更新時(shí)間:2022年08月01日 11:22:10   作者:Code0cean  
本文主要介紹了SpringBoot多數(shù)據(jù)源配置并通過注解實(shí)現(xiàn)動態(tài)切換數(shù)據(jù)源,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1. 環(huán)境準(zhǔn)備

1.1 數(shù)據(jù)庫準(zhǔn)備

一個(gè)本地環(huán)境的MySQL數(shù)據(jù)庫,數(shù)據(jù)庫mydb,創(chuàng)建表t_user

CREATE TABLE `t_user` (
  `c_id` varchar(20) NOT NULL,
  `c_username` varchar(20) DEFAULT NULL,
  `c_password` varchar(20) DEFAULT NULL,
  `c_gender` tinyint(2) DEFAULT NULL,
  PRIMARY KEY (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `mydb`.`t_user`(`c_id`, `c_username`, `c_password`, `c_gender`) VALUES ('1', '思思', '123', 1);

一個(gè)云服務(wù)器的MySQL數(shù)據(jù)庫,創(chuàng)建數(shù)據(jù)庫book_db,創(chuàng)建表t_userinfo。

CREATE TABLE `t_user_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶id',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用戶名',
  `password` varchar(255) DEFAULT NULL COMMENT '登錄密碼',
  `areaObj` varchar(255) DEFAULT NULL COMMENT '所在學(xué)院',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `sex` tinyint(255) DEFAULT NULL COMMENT '性別',
  `user_photo` varchar(255) DEFAULT NULL COMMENT '學(xué)生照片',
  `birthday` varchar(20) DEFAULT NULL COMMENT '出生日期',
  `telephone` varchar(20) DEFAULT NULL COMMENT '聯(lián)系電話',
  `address` varchar(255) DEFAULT NULL COMMENT '家庭地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `book_db`.`t_user_info`(`id`, `user_name`, `password`, `areaObj`, `name`, `sex`, `user_photo`, `birthday`, `telephone`, `address`) VALUES (1, '張三', '123', '哈爾濱', '張三散', 1, '123', '02-16', '15756892458', '黑龍江省哈爾濱市');

創(chuàng)建數(shù)據(jù)庫chatroom,創(chuàng)建表admin。

CREATE TABLE `admin` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL COMMENT '登錄賬號',
  `nickname` varchar(20) NOT NULL COMMENT '昵稱',
  `password` varchar(255) NOT NULL COMMENT '密碼',
  `user_profile` varchar(255) DEFAULT NULL COMMENT '管理員頭像',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

INSERT INTO `chatroom`.`admin`(`id`, `username`, `nickname`, `password`, `user_profile`) VALUES (1, 'admin', '系統(tǒng)管理員', '$2a$10$PyloUEVGuO0fUZdfeIaROOTluRmccl.Scifa8S7Os0Wt.s4bDkb', 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1784117537,3335593911&fm=26&gp=0.jpg');

1.2 項(xiàng)目創(chuàng)建

創(chuàng)建SpringBoot項(xiàng)目,整合MyBatis-Plus。pom.xml引入的依賴:

<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>

		<!--mybatis plus-->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.0.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!--druid-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.10</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.9</version>
		</dependency>

	</dependencies>

配置讀取resource文件夾下的mapper文件

	<build>
		<resources>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.xml</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
			</resource>
		</resources>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>

		</plugins>
	</build>

2. ThreadLocal類介紹

http://www.dbjr.com.cn/article/257530.htm

3. AbstractRoutingDataSource類介紹

Spring Boot提供了AbstractRoutingDataSource 根據(jù)用戶定義的規(guī)則選擇要使用的數(shù)據(jù)源,這樣我們可以在每次數(shù)據(jù)庫操作前設(shè)置使用的數(shù)據(jù)源,實(shí)現(xiàn)可動態(tài)路由的數(shù)據(jù)源。它的抽象方法determineCurrentLookupKey() 決定使用哪個(gè)數(shù)據(jù)源。

在這里插入圖片描述

getConnection()獲取數(shù)據(jù)庫連接,根據(jù)查找lookup key鍵對不同目標(biāo)數(shù)據(jù)源的調(diào)用,通常是通過(但不一定)某些線程綁定的事物上下文來實(shí)現(xiàn)。通過這我們知道可以實(shí)現(xiàn):數(shù)據(jù)源的動態(tài)切換,在程序運(yùn)行時(shí),把數(shù)據(jù)源動態(tài)織入到程序中,靈活得進(jìn)行數(shù)據(jù)源切換,從而可以不依賴中間件,實(shí)現(xiàn)讀寫分離功能。

AbstractRoutingDataSource實(shí)現(xiàn)邏輯:

  • 繼承抽象類AbstractRoutingDataSource,并實(shí)現(xiàn)determineCurrentLookupKey()方法。自定義LookupKey的選擇規(guī)則。
  • 把配置的多個(gè)數(shù)據(jù)源放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中(使用setDefaultTargetDataSource和setTargetDataSources方法),然后通過afterPropertiesSet()方法將數(shù)據(jù)源分別進(jìn)行復(fù)制到AbstractRoutingDataSource的resolvedDataSources屬性和resolvedDefaultDataSource屬性中。

在這里插入圖片描述

調(diào)用AbstractRoutingDataSource的getConnection()的方法的時(shí)候,先調(diào)用determineTargetDataSource()方法返回DataSource在進(jìn)行g(shù)etConnection()。

在這里插入圖片描述

determineTargetDataSource()方法通過調(diào)用determineCurrentLookupKey() 方法返回的lookupKey決定使用哪個(gè)數(shù)據(jù)源。

在這里插入圖片描述

4. 具體實(shí)現(xiàn)

4.1 定義數(shù)據(jù)源枚舉類

定義數(shù)據(jù)源枚舉類DataSourceTypeEnum

public enum DataSourceTypeEnum {
    /**
     * chatroom
     */
    CHATROOM("chatroom"),
    /**
     * book_db
     */
    BOOK_DB("book_db"),
    /**
     * mydb
     */
    MY_DB("mydb");

    private final String name;

    DataSourceTypeEnum(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

4.2 創(chuàng)建動態(tài)多數(shù)據(jù)源類

定義一個(gè)動態(tài)多數(shù)據(jù)源類DynamicDataSource用于管理不同線程間多個(gè)數(shù)據(jù)源的選擇和切換,擴(kuò)展 Spring 提供的 AbstractRoutingDataSource 抽象類,重寫 determineCurrentLookupKey 方法,其中的determineCurrentLookupKey() 方法用于決定使用哪個(gè)數(shù)據(jù)源。

public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * ThreadLocal 用于提供線程局部變量,在多線程環(huán)境可以保證各個(gè)線程里的變量獨(dú)立于其它線程里的變量。
     * 也就是說 ThreadLocal 可以為每個(gè)線程創(chuàng)建一個(gè)【單獨(dú)的變量副本】,相當(dāng)于線程的 private static 類型變量。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 決定使用哪個(gè)數(shù)據(jù)源之前需要把多個(gè)數(shù)據(jù)源的信息以及默認(rèn)數(shù)據(jù)源信息配置好
     *
     * @param defaultTargetDataSource 默認(rèn)數(shù)據(jù)源
     * @param targetDataSources       目標(biāo)數(shù)據(jù)源
     */
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    /**
     * determineCurrentLookupKey決定使用哪個(gè)數(shù)據(jù)庫
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        CONTEXT_HOLDER.set(dataSource);
    }

    public static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }
    
    public static void clearDataSource() {
        CONTEXT_HOLDER.remove();
    }
}

4.3 創(chuàng)建動態(tài)多數(shù)據(jù)源配置類

DynamicDataSourceConfig類作為配置類,讀取配置文件的三個(gè)數(shù)據(jù)源的配置,創(chuàng)建對應(yīng)DataSource類型的Bean。

@Configuration
public class DynamicDataSourceConfig {

    @Bean(name="chatroom")
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource dataSource1(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name ="book_db")
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource dataSource2(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name="mydb")
    @ConfigurationProperties("spring.datasource.druid.third")
    public DataSource dataSource3(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name="dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>(5);
        targetDataSources.put(DataSourceTypeEnum.CHATROOM.getName(), dataSource1());
        targetDataSources.put(DataSourceTypeEnum.BOOK_DB.getName(), dataSource2());
        targetDataSources.put(DataSourceTypeEnum.MY_DB.getName(), dataSource3());
        return new DynamicDataSource(dataSource1(), targetDataSources);
    }
}

4.4 自定義注解用于指定數(shù)據(jù)源

自定義注解@SpecifyDataSource用于在Service層方法上標(biāo)記要使用哪個(gè)數(shù)據(jù)源。這里定義默認(rèn)使用數(shù)據(jù)源 DataSourceType.CHATROOM。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpecifyDataSource {

    /**
     * @return
     */
    DataSourceTypeEnum value() default DataSourceTypeEnum.CHATROOM;
}

4.5 AOP實(shí)現(xiàn)動態(tài)切換數(shù)據(jù)源

定義數(shù)據(jù)源界面類DataSourceAspect,用于實(shí)現(xiàn)有SpecifyDataSource注解標(biāo)注的方法前切換注解指定的數(shù)據(jù)源。

@Aspect
@Component
@Order(value = 1)
public class DataSourceAspect {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("@annotation(top.javahai.datasource.annotation.SpecifyDataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        SpecifyDataSource ds = method.getAnnotation(SpecifyDataSource.class);
        if (ds == null) {
            DynamicDataSource.setDataSource(DataSourceType.CHATROOM.getName());
            logger.info("set datasource is " + DataSourceType.CHATROOM);
        } else {
            DynamicDataSource.setDataSource(ds.value().getName());
            logger.info("set datasource is " + ds.value().getName());
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.info("clean datasource");
        }
    }
}

5. 測試使用

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

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
# 數(shù)據(jù)源1
spring.datasource.druid.first.url=jdbc:mysql://158.156.444.68:3306/chatroom?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.first.username=root
spring.datasource.druid.first.password=123456
# 數(shù)據(jù)源2
spring.datasource.druid.second.url=jdbc:mysql://158.156.444.68:3306/book_db?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.second.username=root
spring.datasource.druid.second.password=123456

#數(shù)據(jù)源3
spring.datasource.druid.third.url=jdbc:mysql:///mydb?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.third.username=root
spring.datasource.druid.third.password=123456

mybatis-plus.mapper-locations=classpath:mapper/*.xml


#輸出sql執(zhí)行日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

5.2 創(chuàng)建實(shí)體類

創(chuàng)建實(shí)體類Admin

public class Admin implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 登錄賬號
     */
    private String username;

    /**
     * 昵稱
     */
    private String nickname;

    /**
     * 密碼
     */
    private String password;

    /**
     * 管理員頭像
     */
    private String userProfile;

//省略getter/setter方法

創(chuàng)建實(shí)體類TUser

public class TUser implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "c_id", type = IdType.AUTO)
    private Integer cId;

    private String cUsername;

    private String cPassword;

    private Integer cGender;
}

創(chuàng)建實(shí)體類TUserinfo

@TableName(value = "t_user_info")
public class TUserinfo implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * user_name
     */
    private String userName;

    /**
     * 登錄密碼
     */
    private String password;

    /**
     * 所在學(xué)院
     */
    @TableField("areaObj")
    private String areaObj;

    /**
     * 姓名
     */
    private String name;

    /**
     * 性別
     */
    private Integer sex;

    /**
     * 學(xué)生照片
     */
    private String userPhoto;

    /**
     * 出生日期
     */
    private String birthday;

    /**
     * 聯(lián)系電話
     */
    private String telephone;

    /**
     * 家庭地址
     */
    private String address;
}

創(chuàng)建UserVO用于測試

public class UserVO {

    private List<Admin> adminList;
    private List<TUserinfo> tUserinfos;
    private List<TUser> tUsers;
}

5.3 服務(wù)層代碼

@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    public List<Admin> getAll(){
        return this.list(null);
    }
}
@Service
public class TUserinfoServiceImpl extends ServiceImpl<TUserinfoMapper, TUserinfo> implements ITUserinfoService {

    @SpecifyDataSource(value = DataSourceTypeEnum.BOOK_DB)
    public List<TUserinfo> selectAll(){
        return this.list(null);
    }

}
@Service
public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser> implements ITUserService {

    @SpecifyDataSource(value = DataSourceTypeEnum.MY_DB)
    public List<TUser> selectAll(){
        return this.list(null);
    }
}
public interface AdminMapper extends BaseMapper<Admin> {

}

public interface TUserinfoMapper extends BaseMapper<TUserinfo> {

}

public interface TUserMapper extends BaseMapper<TUser> {

}

5.4 控制層代碼

創(chuàng)建接口/test/list用于測試

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private AdminServiceImpl adminService;

    @Autowired
    private TUserinfoServiceImpl userinfoService;

    @Autowired
    private TUserServiceImpl userService;

    @GetMapping("/list")
    public UserVO list(){
        List<Admin> adminList= adminService.getAll();
        List<TUserinfo> tUserinfos = userinfoService.selectAll();
        List<TUser> tUsers = userService.selectAll();
        UserVO userVO = new UserVO();
        userVO.setAdminList(adminList);
        userVO.settUserinfos(tUserinfos);
        userVO.settUsers(tUsers);
        return userVO;
    }
}

瀏覽器請求/test/list

在這里插入圖片描述

查看控制臺輸出,查看數(shù)據(jù)源的切換日志

,

完整Demo代碼地址:https://github.com/JustCoding-Hai/learn-everyday/tree/master/learn-multi_data_source

到此這篇關(guān)于SpringBoot多數(shù)據(jù)源配置并通過注解實(shí)現(xiàn)動態(tài)切換數(shù)據(jù)源的文章就介紹到這了,更多相關(guān)SpringBoot 動態(tài)切換數(shù)據(jù)源內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java多線程之同步工具類CyclicBarrier

    Java多線程之同步工具類CyclicBarrier

    這篇文章主要介紹Java多線程之同步工具類CyclicBarrier,它是一個(gè)同步工具類,它允許一組線程互相等待,直到達(dá)到某個(gè)公共屏障點(diǎn),支持一個(gè)可選的Runnable命令,在一組線程中的最后一個(gè)線程到達(dá)之后,該命令只在每個(gè)屏障點(diǎn)運(yùn)行一次。下面來看文章具體內(nèi)容
    2021-10-10
  • elasticsearch集群cluster示例詳解

    elasticsearch集群cluster示例詳解

    這篇文章主要為大家介紹了elasticsearch集群cluster示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • java 中HashMap實(shí)現(xiàn)原理深入理解

    java 中HashMap實(shí)現(xiàn)原理深入理解

    這篇文章主要介紹了java 中HashMap實(shí)現(xiàn)原理深入理解的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • JVM中的GC初識

    JVM中的GC初識

    GC(Garbage Collection)稱之為垃圾回收,是對內(nèi)存中的垃圾對象,采用一定的算法進(jìn)行內(nèi)存回收的一個(gè)動作,這篇文章主要介紹了JVM中的GC初識,需要的朋友可以參考下
    2022-05-05
  • Java基礎(chǔ)之詳解HashSet的使用方法

    Java基礎(chǔ)之詳解HashSet的使用方法

    今天給大家?guī)淼氖顷P(guān)于Java基礎(chǔ)的相關(guān)知識,文章圍繞著HashSet的使用方法展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • idea手動執(zhí)行maven命令的三種實(shí)現(xiàn)方式

    idea手動執(zhí)行maven命令的三種實(shí)現(xiàn)方式

    這篇文章主要介紹了idea手動執(zhí)行maven命令的三種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • HttpClient實(shí)現(xiàn)調(diào)用外部項(xiàng)目接口工具類的示例

    HttpClient實(shí)現(xiàn)調(diào)用外部項(xiàng)目接口工具類的示例

    下面小編就為大家?guī)硪黄狧ttpClient實(shí)現(xiàn)調(diào)用外部項(xiàng)目接口工具類的示例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • maven項(xiàng)目test執(zhí)行main找不到資源文件的問題及解決

    maven項(xiàng)目test執(zhí)行main找不到資源文件的問題及解決

    這篇文章主要介紹了maven項(xiàng)目test執(zhí)行main找不到資源文件的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring Boot運(yùn)行部署過程圖解

    Spring Boot運(yùn)行部署過程圖解

    這篇文章主要介紹了Spring Boot運(yùn)行部署過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java Scanner如何獲取字符串和帶空格的字符串

    Java Scanner如何獲取字符串和帶空格的字符串

    這篇文章主要介紹了Java Scanner如何獲取字符串和帶空格的字符串問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08

最新評論