在本文中使用Spring Boot 2.4.1+MyBatis-plus+Druid+Sharding-JDBC+MySQL進行讀寫分離的案件講解。
1、數據庫准備
1、192.168.8.162 test1主
2、192.168.8.134 test1從
3、192.168.8.176 test1從
4、192.168.8.162 test2主
5、192.168.8.134 test2從
6、192.168.8.176 test2從
2、准備分庫分表
USE `test1`; DROP TABLE IF EXISTS `t_user_0`; CREATE TABLE `t_user_0` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_1`; CREATE TABLE `t_user_1` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_2`; CREATE TABLE `t_user_2` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_3`; CREATE TABLE `t_user_3` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; USE `test2`; DROP TABLE IF EXISTS `t_user_0`; CREATE TABLE `t_user_0` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_1`; CREATE TABLE `t_user_1` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_2`; CREATE TABLE `t_user_2` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `t_user_3`; CREATE TABLE `t_user_3` ( `id` int(10) NOT NULL, `name` varchar(50) NOT NULL, `sex` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3、上代碼
1、pom.xml配置引入maven依賴
<properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <druid.version>1.1.9</druid.version> <mybatis-plus.version>3.1.1</mybatis-plus.version> <mybatis-plus-stater.version>3.1.2</mybatis-plus-stater.version> <lombok.version>1.16.18</lombok.version> <mybatisplus-spring-boot-starter.version>1.0.5</mybatisplus-spring-boot-starter.version> </properties> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <!-- Mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>${mybatisplus-spring-boot-starter.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus-stater.version}</version> </dependency> <!--shardingsphere數據分片、脫敏工具--> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.1.0</version> </dependency>
2、在application.yml中配置使用mybatis-plus及引用數據源及分庫分表信息
spring: # 配置說明地址 https://test1.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/configuration/config-spring-boot/#%E6%95%B0%E6%8D%AE%E5%88%86%E7%89%87 shardingsphere: # 數據庫 datasource: # 主庫1 ,master數據庫 master0: ### 數據源類別 type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.8.162:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 username: root password: root # 主庫1從庫1 ,slave數據庫 master0slave0: ### 數據源類別 type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.8.134:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 username: root password: root # 主庫1從庫2 ,slave數據庫 master0slave1: ### 數據源類別 type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.8.176:3306/test1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 username: root password: root # 主庫2 ,master數據庫 master1: ### 數據源類別 type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.8.162:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 username: root password: root # 主庫2從庫1 ,slave數據庫 master1slave0: ### 數據源類別 type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.8.134:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 username: root password: root # 主庫2從庫2 ,slave數據庫 master1slave1: ### 數據源類別 type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.8.176:3306/test2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8 username: root password: root # 數據庫的別名 names: master0,master0slave0,master0slave1,master1,master1slave0,master1slave1 sharding: # 設置綁定表,用逗號分割 binding-tables: t_user master-slave-rules: ds0: name: ds0datasource # 查詢時的負載均衡算法,目前有2種算法,round_robin(輪詢)和random(隨機), # 算法接口是io.shardingjdbc.core.api.algorithm.masterslave.MasterSlaveLoadBalanceAlgorithm。 # 實現類有RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm。 load-balance-algorithm-type: round_robin # 主數據源名稱 master-data-source-name: master0 # 從數據源名稱,多個用逗號隔開 slave-data-source-names: master0slave0, master0slave1 ds1: name: ds1datasource # 查詢時的負載均衡算法,目前有2種算法,round_robin(輪詢)和random(隨機), # 算法接口是io.shardingjdbc.core.api.algorithm.masterslave.MasterSlaveLoadBalanceAlgorithm。 # 實現類有RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm。 load-balance-algorithm-type: round_robin # 主數據源名稱 master-data-source-name: master1 # 從數據源名稱,多個用逗號隔開 slave-data-source-names: master1slave0,master1slave1 tables: ### t_user分庫分表配置 t_user: actual-data-nodes: ds$->{0..1}.t_user_$->{0..3} database-strategy: standard: precise-algorithm-class-name: com.demo.shardingjdbc.MyDBPreciseShardingAlgorithm sharding-column: id table-strategy: standard: precise-algorithm-class-name: com.demo.shardingjdbc.MyTablePreciseShardingAlgorithm sharding-column: id #### mybatis-plus ### mybatis-plus: # 如果是放在src/main/java目錄下 classpath:/com/yourpackage/*/mapper/*Mapper.xml # 如果是放在resource目錄 classpath:/mapper/*Mapper.xml mapper-locations: classpath:mapper/*.xml #實體掃描,多個package用逗號或者分號分隔 type-aliases-package: com.demo.shardingjdbc.entity configuration: map-underscore-to-camel-case: true cache-enabled: false #主鍵類型 0:"數據庫ID自增", 1:"用戶輸入ID",2:"全局唯一ID (數字類型唯一ID)", 3:"全局唯一ID UUID"; global-config: db-config: id-type: auto #字段策略 0:"忽略判斷",1:"非 NULL 判斷"),2:"非空判斷" field-strategy: not-empty #駝峰下划線轉換 column-underline: true #邏輯刪除配置 logic-delete-value: 0 logic-not-delete-value: 1 db-type: mysql #刷新mapper 調試神器 refresh: false
3、配置分庫分表分片規則(結合application.yml)
分庫規則(結合pplication.yml中database-strategy)
package com.demo.shardingjdbc; import java.util.Collection; import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm; import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue; /** * 自定義實現 精准分片算法(PreciseShardingAlgorithm)接口 * 數據表table的精准分片 * @author hzy * */ public class MyDBPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> { @Override public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) { for (String tableName : availableTargetNames) { if (tableName.endsWith(shardingValue.getValue() % 2 + "")) { return tableName; } } throw new IllegalArgumentException(); } }
分表規則(結合pplication.yml中table-strategy)
package com.demo.shardingjdbc; import java.util.Collection; import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm; import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue; /** * 自定義實現 精准分片算法(PreciseShardingAlgorithm)接口 * 數據表table的精准分片 * @author hzy * */ public class MyTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> { @Override public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) { for (String tableName : availableTargetNames) { if (tableName.endsWith(shardingValue.getValue() % 4 + "")) { return tableName; } } throw new IllegalArgumentException(); } }
4、mybatis-plus操作數據庫配置
User.java
package com.demo.shardingjdbc.entity; import java.io.Serializable; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; /** * @Description: (User)實體類 * @Version 1.0 */ @Data @TableName("t_user") public class User implements Serializable { private static final long serialVersionUID = 358157380505039579L; /** * 用戶id */ @TableId(type = IdType.INPUT) private Integer id; /** * 用戶名稱 */ private String name; /** * 性別 */ private String sex; }
mapper
package com.demo.shardingjdbc.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.demo.shardingjdbc.entity.User; /** * (t_user)表數據庫訪問層 * */ public interface UserMapper extends BaseMapper<User> { }
5、mybatis-plus配置MybatisPlusConfig
package com.demo.shardingjdbc.config; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; /** * @Description: */ //Spring boot方式 @EnableTransactionManagement @Configuration //掃描的mapper文件路徑 @MapperScan(value = "com.demo.shardingjdbc.mapper") public class MybatisPlusConfig { /** * 分頁插件 */ @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } }
6、service層
package com.demo.shardingjdbc.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.demo.shardingjdbc.entity.User; import com.demo.shardingjdbc.mapper.UserMapper; import com.demo.shardingjdbc.service.UserService; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> selectList() { QueryWrapper<User> wrapper = new QueryWrapper<User>(); wrapper.orderByAsc("id"); List<User> users = userMapper.selectList(wrapper); return users; } @Override public int insert(User user) { return userMapper.insert(user); } }
7、controller控制層
package com.demo.shardingjdbc.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.demo.shardingjdbc.entity.User; import com.demo.shardingjdbc.service.UserService; import lombok.extern.slf4j.Slf4j; /** * @ClassName TestController * @Description TestController * @Version */ @RestController @Slf4j public class UserController { @Autowired private UserService userService; /** * 用戶列表 * * @return */ @RequestMapping("/userList") public List<User> userList() { log.info("********TestController userList()"); List<User> users = userService.selectList(); return users; } /** * 保存用戶 * * @return */ @GetMapping("/add") public Object add() { int num = 0; for (int i = 1; i <= 300; i++) { User user = new User(); user.setId(i); user.setName("hzy" + (i)); String sex = (i % 2 == 0) ? "男" : "女"; user.setSex(sex); int resutl = userService.insert(user); log.info("insert:" + user.toString() + " result:" + resutl); num = num + resutl; } return num; } }
完成。在瀏覽器上執行localhost:8080/add,然后去數據庫中查詢,可以看到test1.t_user_0、test1.t_user_2、test2.t_user_1、test2.t_user_3分別插入了數據。
然后訪問localhost:8080/userList,可以查詢數據庫中四個表中的所有數據。可見Sharding-JDBC在插入數據的時候,根據數據分庫分表策略,將數據存儲在不同庫不同表中,查詢時將數據庫從多個表中查詢並聚合。