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ù)源的情況,比如多租戶的場(chǎng)景,系統(tǒng)登錄時(shí)需要根據(jù)用戶信息切換到用戶對(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)建用戶表,用來(lái)測(cè)試數(shù)據(jù)源,SQL腳本如下。
-- ---------------------------------------------------- -- 用戶 -- ---------------------------------------------------- -- 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 '用戶名', `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='用戶';
新建工程
新建一個(gè)Spring Boot工程,最終代碼結(jié)構(gòu)如下。
添加依賴
添加Spring Boot,Spring Aop,Mybatis,MySQL,Swagger相關(guān)依賴。Swagger方便用來(lái)測(cè)試接口。
pom.xml
<?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
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)類
啟動(dòng)類添加 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ō)。
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ù)源配置類
創(chuàng)建一個(gè)數(shù)據(jù)源配置類,主要做以下幾件事情:
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ù)源了。
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ù)源類
我們上一步把這個(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)獲取要操作的數(shù)據(jù)源了。
動(dòng)態(tài)數(shù)據(jù)源類集成了Spring提供的AbstractRoutingDataSource類,AbstractRoutingDataSource 中 獲取數(shù)據(jù)源的方法就是 determineTargetDataSource,而此方法又通過(guò) determineCurrentLookupKey 方法獲取查詢數(shù)據(jù)源的key。
所以如果我們需要?jiǎng)討B(tài)切換數(shù)據(jù)源,就可以通過(guò)以下兩種方式定制:
1. 覆寫 determineCurrentLookupKey 方法
通過(guò)覆寫 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ò)覆寫 determineTargetDataSource,因?yàn)閿?shù)據(jù)源就是在這個(gè)方法創(chuàng)建并返回的,所以這種方式就比較自由了,支持到任何你希望的地方讀取數(shù)據(jù)源信息,只要最終返回一個(gè) DataSource 的實(shí)現(xiàn)類即可。比如你可以到數(shù)據(jù)庫(kù)、本地文件、網(wǎng)絡(luò)接口等方式讀取到數(shù)據(jù)源信息然后返回相應(yīng)的數(shù)據(jù)源對(duì)象就可以了。
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)類 * @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)類對(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)完成的。在任何想要進(jìn)行切換數(shù)據(jù)源的時(shí)候都可以通過(guò)調(diào)用這個(gè)類的方法實(shí)現(xiàn)切換。比如系統(tǒng)登錄時(shí),根據(jù)用戶信息調(diào)用這個(gè)類的數(shù)據(jù)源切換方法切換到用戶對(duì)應(yīng)的數(shù)據(jù)庫(kù)。
主要方法介紹:
1. 切換數(shù)據(jù)源
在任何想要進(jìn)行切換數(shù)據(jù)源的時(shí)候都可以通過(guò)調(diào)用這個(gè)類的方法實(shí)現(xiàn)切換。
/** * 切換數(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è)置。
/** * 重置數(shù)據(jù)源 */ public static void clearDataSourceKey() { contextHolder.remove(); }
3. 獲取當(dāng)前數(shù)據(jù)源key
/** * 獲取數(shù)據(jù)源 * @return */ public static String getDataSourceKey() { return contextHolder.get(); }
完整代碼如下
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。
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ù)源。
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)的處理代碼就完成了。
編寫用戶業(yè)務(wù)代碼
接下來(lái)編寫用戶查詢業(yè)務(wù)代碼,用來(lái)進(jìn)行測(cè)試,只需添加一個(gè)查詢接口即可。
編寫一個(gè)控制器,包含兩個(gè)查詢方法,分別注解 master 和 slave 數(shù)據(jù)源。
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; /** * 用戶控制器 * @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ō)明的,直接貼代碼了。
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
<?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
package com.louis.springboot.dynamic.datasource.service; import java.util.List; import com.louis.springboot.dynamic.datasource.model.SysUser; /** * 用戶管理 * @author Louis * @date Oct 31, 2018 */ public interface SysUserService { /** * 查找全部用戶信息 * @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; /** * 查找全部用戶信息 * @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ù)源)
user/findAll2 (slave數(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ǎng)站的支持!
- spring boot task實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建定時(shí)任務(wù)的方法
- spring boot + mybatis實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源實(shí)例代碼
- Springboot整個(gè)Quartz實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)的示例代碼
- Quartz+Spring Boot實(shí)現(xiàn)動(dòng)態(tài)管理定時(shí)任務(wù)
- springboot整合Quartz實(shí)現(xiàn)動(dòng)態(tài)配置定時(shí)任務(wù)的方法
- Spring boot 應(yīng)用實(shí)現(xiàn)動(dòng)態(tài)刷新配置詳解
相關(guān)文章
java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能
在最近的開發(fā)中遇到了敏感詞過(guò)濾,便去網(wǎng)上查閱了很多敏感詞過(guò)濾的資料,在這里也和大家分享一下自己的理解。下面這篇文章主要給大家介紹了關(guān)于java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-06-06Java實(shí)現(xiàn)簡(jiǎn)單的銀行管理系統(tǒng)的示例代碼
這篇文章主要介紹了如何利用Java實(shí)現(xiàn)簡(jiǎn)單的銀行管理系統(tǒng),可以實(shí)現(xiàn)存款,取款,查詢等功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-09-09Javaweb請(qǐng)求轉(zhuǎn)發(fā)及重定向?qū)崿F(xiàn)詳解
這篇文章主要介紹了Javaweb請(qǐng)求轉(zhuǎn)發(fā)及重定向?qū)崿F(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07Java中垃圾回收器GC對(duì)吞吐量的影響測(cè)試
這篇文章主要介紹了Java中垃圾回收器GC對(duì)吞吐量的影響測(cè)試,本文算是一個(gè)對(duì)垃圾回收器GC的優(yōu)化文章,需要的朋友可以參考下2014-09-09