SpringBoot整合MyBatisPlus配置動態資料來源
推文:2018開源中國最受歡迎的中國軟體MyBatis-Plus
MybatisPlus特性
- 無侵入:只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑
- 損耗小:啟動即會自動注入基本 CURD,效能基本無損耗,直接物件導向操作
- 強大的 CRUD 操作:內建通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求
- 支援 Lambda 形式呼叫:通過 Lambda 表示式,方便的編寫各類查詢條件,無需再擔心欄位寫錯
- 支援多種資料庫:支援 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多種資料庫
- 支援主鍵自動生成:支援多達 4 種主鍵策略(內含分散式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題
- 支援 XML 熱載入:Mapper 對應的 XML 支援熱載入,對於簡單的 CRUD 操作,甚至可以無 XML 啟動
- 支援 ActiveRecord 模式:支援 ActiveRecord 形式呼叫,實體類只需繼承 Model 類即可進行強大的 CRUD 操作
- 支援自定義全域性通用操作:支援全域性通用方法注入( Write once, use anywhere )
- 支援關鍵詞自動轉義:支援資料庫關鍵詞(order、key......)自動轉義,還可自定義關鍵詞
- 內建程式碼生成器:採用程式碼或者 Maven 外掛可快速生成 Mapper 、 Model 、 Service 、 Controller 層程式碼,支援模板引擎,更有超多自定義配置等您來使用
- 內建分頁外掛:基於 MyBatis 物理分頁,開發者無需關心具體操作,配置好外掛之後,寫分頁等同於普通 List 查詢
- 內建效能分析外掛:可輸出 Sql 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢
- 內建全域性攔截外掛:提供全表 delete 、 update 操作智慧分析阻斷,也可自定義攔截規則,預防誤操作
- 內建 Sql 注入剝離器:支援 Sql 注入剝離,有效預防 Sql 注入攻擊
快速開始
初始化測試資料表:
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主鍵ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年齡',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY (id)
);
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
父工程依賴
該工程用於依賴管理,pom如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
<mybatis-plus-version>3.1.1</mybatis-plus-version>
<mysql-driver-version>5.1.47</mysql-driver-version>
<druid-version>1.1.10</druid-version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
建立MyBaitsPlus工程
依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<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>
<!-- mybatis plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-driver-version}</version>
</dependency>
<!-- druid資料連線池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
properties配置
在這裡配置資料庫連線,以及資料連線池與mybatisplus的配置等
server.port=8080
spring.application.name=mybatis
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.maxActive=20
spring.datasource.druid.maxWait=60000
spring.datasource.druid.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.minEvictableIdleTimeMillis=300000
spring.datasource.druid.validationQuery=SELECT 1 FROM DUAL
spring.datasource.druid.testWhileIdle=true
spring.datasource.druid.testOnBorrow=false
spring.datasource.druid.testOnReturn=false
spring.datasource.druid.poolPreparedStatements=true
spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.druid.filters=stat,slf4j
spring.datasource.druid.connectionProperties=druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
spring.datasource.druid.web-stat-filter.enabled=true
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.allow=127.0.0.1,192.168.163.1
spring.datasource.druid.stat-view-servlet.deny=192.168.1.73
spring.datasource.druid.stat-view-servlet.reset-enable=false
#Druid 管理賬號
spring.datasource.druid.stat-view-servlet.login-username=admin
#Druid 管理密碼
spring.datasource.druid.stat-view-servlet.login-password=123456
#com.simple.spring.boot.mapper 該包列印DEBUG級別日誌
logging.level.com.simple.spring.boot.mapper=debug
#mybatis plus mapper檔案路徑
mybatis-plus.mapperLocations=classpath:/mybatis/mapper/*.xml
#mybaits plus 實體類路徑
mybatis-plus.typeAliasesPackage=com.simple.spring.**.entities
mybatis-plus.typeEnumsPackage=
#資料庫相關配置
#主鍵型別 AUTO:"資料庫ID自增", INPUT:"使用者輸入ID",ID_WORKER:"全域性唯一ID (數字型別唯一ID)", UUID:"全域性唯一ID UUID";
mybatis-plus.global-config.db-config.id-type=UUID
#欄位策略 IGNORED:"忽略判斷",NOT_NULL:"非 NULL 判斷"),NOT_EMPTY:"非空判斷"
mybatis-plus.global-config.db-config.field-strategy=not_empty
#駝峰下劃線轉換
mybatis-plus.global-config.db-config.column-underline=true
#資料庫大寫下劃線轉換
#capital-mode: true
#邏輯刪除配置
mybatis-plus.global-config.db-config.logic-delete-value=0
mybatis-plus.global-config.db-config.logic-not-delete-value= 1
#mybatis-plus.global-config.db-config.db-type= sqlserver
#重新整理mapper 除錯神器
mybatis-plus.global-config.refresh=true
# 原生配置
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
mybatis-plus.configuration.call-setters-on-nulls =true
常規增刪改查實現
建立實體類:
**
* 實體類
* @author: SimpleWu
* @date: 2019/5/25
*/
@Data
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
該lombok
外掛省去getset方法。
建立UserMapper
介面,並且實現BaseMapper<User>
這裡我們指定實體類為user
可直接使用介面中的方法。
查詢所有資料
public List<User> getList(){ return userMapper.selectList(null); }
查詢資料帶查詢條件
public List<User> getListQuery(){ User user = new User(); user.setName("SimpleWu"); Wrapper<User> wrapper = new QueryWrapper<>(user); return userMapper.selectList(wrapper); }
查詢帶分頁
public IPage<User> page(){ int currentPage = 1 ; //當前頁 int pageSize = 2 ;//每頁大小 IPage<User> page = new Page(currentPage,pageSize); page = userMapper.selectPage(page,null); return page; }
根據實體類新增資料
@Transactional//本地事務開啟 public int insert(){ User user = new User(); user.setId(6l); user.setName("SimpleWu"); user.setAge(100); user.setEmail("SimpleWu@gmail.com"); return userMapper.insert(user); }
根據主鍵刪除資料
@Transactional//本地事務開啟 public int deleteById(){ int userId = 6; return userMapper.deleteById(userId); }
根據ID更新資料
@Transactional//本地事務開啟 public int updateById(){ User user = new User(); user.setId(5l); user.setName("update"); user.setAge(100); user.setEmail("update@email.com"); return userMapper.updateById(user); }
條件構造器
- UpdateWrapper 用於增刪改構造條件
- QueryWrapper 用於查詢構造條件
Transactional//本地事務開啟 public int updateWrapperUser(){ User user = new User(); user.setId(5l); user.setName("update"); user.setAge(100); user.setEmail("update@email.com"); User updateWrapperUser = new User(); updateWrapperUser.setId(1l); /** * 修改 UpdateWrapper * 查詢 QueryWrapper */ Wrapper<User> wrapper = new UpdateWrapper<>(updateWrapperUser); return userMapper.update(user,wrapper); }
Mapper介面繫結Mapper檔案
properites中配置既可
#掃描mybatis/mapper下面的所有xml mybatis-plus.mapperLocations=classpath:/mybatis/mapper/*.xml
UserMapper介面測試
public interface UserMapper extends BaseMapper<User> {
Map<String,Object> queryUser(@Param("USER_ID") String userId);
}
UserMapper.xml,如下:
<select id="queryUser" resultType="java.util.HashMap" parameterType="java.lang.String">
SELECT
ID,
NAME
FROM
USER
WHERE ID = #{USER_ID}
</select>
執行SQL:
public Map<String,Object> myMapper(){
return userMapper.queryUser("2");
}
在SpringBoot中使用MybatisPlus分頁需要注入Bean,並且在啟動類上使用@MapperScan("com.simple.spring.boot.mapper")
掃描mapper檔案路徑如下:
@SpringBootApplication
@MapperScan("com.simple.spring.boot.mapper")
public class MybatisPlusApplication {
/**
* 分頁外掛註冊
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
public static void main(String[] args) {
SpringApplication.run(MybatisPlusApplication.class, args);
}
}
使用MyBatisPlus可以為我們減少很多很多的程式碼,不過需要編寫實體類,有失必有得。
配置動態資料來源
dynamic-datasource-spring-boot-starter
是一個基於springboot
的快速整合多資料來源的啟動器。
優勢
網上關於動態資料來源的切換的文件有很多,核心只有兩種。
- 構建多套環境,優勢是方便控制也容易整合一些簡單的分散式事務,缺點是非動態同時程式碼量較多,配置難度大。
- 基於spring提供原生的
AbstractRoutingDataSource
,參考一些文件自己實現切換。
如果你的資料來源較少,場景不復雜,選擇以上任意一種都可以。如果你需要更多特性,請嘗試本動態資料來源。
- 資料來源分組,適用於多種場景 純粹多庫 讀寫分離 一主多從 混合模式。
- 簡單整合Druid資料來源監控多資料來源,簡單整合Mybatis-Plus簡化單表,簡單整合P6sy格式化sql,簡單整合Jndi資料來源。
- 簡化Druid和HikariCp配置,提供全域性引數配置。
- 提供自定義資料來源來源(預設使用yml或properties配置)。
- 專案啟動後能動態增減資料來源。
- 使用spel動態引數解析資料來源,如從session,header和引數中獲取資料來源。(多租戶架構神器)
- 多層資料來源巢狀切換。(一個業務ServiceA呼叫ServiceB,ServiceB呼叫ServiceC,每個Service都是不同的資料來源)
- 使用正則匹配或spel表示式來切換資料來源(實驗性功能)。
劣勢
不能使用多資料來源事務(同一個資料來源下能使用事務),網上其他方案也都不能提供。
如果你需要使用到分散式事務,那麼你的架構應該到了微服務化的時候了。
如果呼聲強烈,專案達到800 star,作者考慮整合分散式事務。
PS: 如果您只是幾個資料庫但是有強烈的需求分散式事務,建議還是使用傳統方式自己構建多套環境整合atomic這類,網上百度很多。
約定
- 本框架只做 切換資料來源 這件核心的事情,並不限制你的具體操作,切換了資料來源可以做任何CRUD。
- 配置檔案所有以下劃線
_
分割的資料來源 首部 即為組的名稱,相同組名稱的資料來源會放在一個組下。 - 切換資料來源即可是組名,也可是具體資料來源名稱,切換時預設採用負載均衡機制切換。
- 預設的資料來源名稱為 master ,你可以通過spring.datasource.dynamic.primary修改。
- 方法上的註解優先於類上註解。
建議
強烈建議在 主從模式 下遵循普遍的規則,以便他人能更輕易理解你的程式碼。
主資料庫 建議 只執行 INSERT
UPDATE
DELETE
操作。
從資料庫 建議 只執行 SELECT
操作。
快速開始
加入依賴:
<!-- 動態資料來源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
註釋掉原來的資料庫配置,加入:
#設定預設的資料來源或者資料來源組,預設值即為master
spring.datasource.dynamic.primary=master
#主庫配置
spring.datasource.dynamic.datasource.master.username=root
spring.datasource.dynamic.datasource.master.password=root
spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&characterEncoding=utf8
#從庫配置
spring.datasource.dynamic.datasource.slave_1.username=root
spring.datasource.dynamic.datasource.slave_1.password=root
spring.datasource.dynamic.datasource.slave_1.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.dynamic.datasource.slave_1.url=jdbc:mysql://localhost:3307/mybatis?useSSL=false&characterEncoding=utf8
使用 @DS 切換資料來源。
@DS("master")
public List<User> getListQuery(){
User user = new User();
user.setName("SimpleWu");
Wrapper<User> wrapper = new QueryWrapper<>(user);
return userMapper.selectList(wrapper);
}
@DS("slave_1")
public IPage<User> page(){
int currentPage = 1 ; //當前頁
int pageSize = 2 ;//每頁大小
IPage<User> page = new Page(currentPage,pageSize);
page = userMapper.selectPage(page,null);
return page;
}
@DS 可以註解在方法上和類上,同時存在方法註解優先於類上註解。
註解在service實現或mapper介面方法上,但強烈不建議同時在service和mapper註解。 (可能會有問題)
如果不加入主鍵則使用預設資料來源。
DruidDataSourceAutoConfigure
會注入一個DataSourceWrapper
,其會在原生的spring.datasource
下找url,username,password
等。而我們動態資料來源的配置路徑是變化的,所以需要排除:
spring:
autoconfigure:
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
或者在類上排除:
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
然後更換properties配置資訊:
#公共配置 Druid登入賬號 密碼
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=123456
spring.datasource.dynamic.druid.initial-size=5
spring.datasource.dynamic.druid.min-idle=5
spring.datasource.dynamic.druid.maxActive=20
spring.datasource.dynamic.druid.maxWait=60000
spring.datasource.dynamic.druid.timeBetweenEvictionRunsMillis=60000
spring.datasource.dynamic.druid.minEvictableIdleTimeMillis=300000
spring.datasource.dynamic.druid.validationQuery=SELECT 1 FROM DUAL
spring.datasource.dynamic.druid.testWhileIdle=true
spring.datasource.dynamic.druid.testOnBorrow=false
spring.datasource.dynamic.druid.testOnReturn=false
spring.datasource.dynamic.druid.poolPreparedStatements=true
spring.datasource.dynamic.druid.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.dynamic.druid.filters=stat,slf4j
spring.datasource.dynamic.druid.connectionProperties=druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
spring.datasource.dynamic.druid.web-stat-filter.enabled=true
spring.datasource.dynamic.druid.web-stat-filter.url-pattern=/*
spring.datasource.dynamic.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
spring.datasource.dynamic.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.dynamic.druid.stat-view-servlet.allow=127.0.0.1,192.168.163.1
spring.datasource.dynamic.druid.stat-view-servlet.deny=192.168.1.73
spring.datasource.dynamic.druid.stat-view-servlet.reset-enable=false
本篇程式碼案例地址:
https://github.com/450255266/open-doubi