Spring Boot整合Sharding-JDBC實現分庫分表+讀寫分離io.shardingsphere(4)
阿新 • • 發佈:2021-01-19
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依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--springboot整合mybatis的依賴 --> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 這裡用的是sharding-jdbc-spring-boot-starter 需要注意的是,此時druid不能用spring-boot-starter版本的,需要用正常的包: --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>io.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>3.1.0.M1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency>
2、在application.yml中配置引用資料來源及分庫分表資訊
mybatis.config-location: classpath:META-INF/mybatis-config.xml spring: profiles: active: sharding-tbl-ms main: allow-bean-definition-overriding: true sharding: jdbc: ### 資料庫 dataSource: ### 資料庫的別名 names: ds-master-0,ds-master-1,ds-master-0-slave-0,ds-master-0-slave-1,ds-master-1-slave-0,ds-master-1-slave-1 # 主庫1 ,master資料庫 ds-master-0: ### 資料來源類別 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 maxPoolSize: 20 ### 主庫1從庫1 ,slave資料庫 ds-master-0-slave-0: ### 資料來源類別 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 maxPoolSize: 20 ### 主庫1從庫1 ,slave資料庫 ds-master-0-slave-1: ### 資料來源類別 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 maxPoolSize: 20 # 主庫2 ,master資料庫 ds-master-1: ### 資料來源類別 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 maxPoolSize: 20 ### 主庫2從庫1 ,slave資料庫 ds-master-1-slave-0: ### 資料來源類別 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 maxPoolSize: 20 ### 主庫2從庫2 ,slave資料庫 ds-master-1-slave-1: ### 資料來源類別 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 maxPoolSize: 20 props: sql: show: true config: masterslave: # 配置讀寫分離 # 配置從庫選擇策略,提供輪詢與隨機,這裡選擇用輪詢//random 隨機 //round-robin 輪詢 load-balance-algorithm-type: round-robin name: datasource sharding: master-slave-rules: ds_0: ###配置的是主庫的資料庫名,本案例為ds-master-0,其中ds_0為分割槽名。 master-data-source-name: ds-master-0 ###配置的是從庫的資料庫名,本案例為ds-master-0-slave-0,ds-master-0-slave-1 slave-data-source-names: ds-master-0-slave-0,ds-master-0-slave-1 ds_1: ###配置的是主庫的資料庫名,本案例為ds-master-1,其中ds_1為分割槽名。 master-data-source-name: ds-master-1 ###配置的是從庫的資料庫名,本案例為ds-master-1-slave-0,ds-master-1-slave-1 slave-data-source-names: ds-master-1-slave-0,ds-master-1-slave-1 tables: ###需要分表的表名 t_user: ###配置的分表資訊,真實的資料庫資訊。ds_0.t_user_$->{0…3},表示讀取ds_0資料來源的user_0、user_1、user_2、user_3。 actual-data-nodes: ds_$->{0..1}.t_user_$->{0..3} database-strategy: standard: ###是配置資料分庫的策略的類,這裡是自定義的類MyDBPreciseShardingAlgorithm precise-algorithm-class-name: com.demo.shardingjdbc.MyDBPreciseShardingAlgorithm ###配置的資料分表的欄位,是根據id來分的 sharding-column: id table-strategy: standard: ###是配置資料分表的策略的類,這裡是自定義的類MyTablePreciseShardingAlgorithm precise-algorithm-class-name: com.demo.shardingjdbc.MyTablePreciseShardingAlgorithm ###配置的資料分表的欄位,是根據id來分的 sharding-column: id
3、配置分庫分表分片規則(結合application.yml)
分庫規則(結合pplication.yml中database-strategy)
package com.demo.shardingjdbc; import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue; import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm; import java.util.Collection; /** * 自定義分片演算法 * * @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 io.shardingsphere.api.algorithm.sharding.PreciseShardingValue; import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm; import java.util.Collection; /** * 自定義分片演算法 * * @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操作資料庫配置
User.java
package com.demo.shardingjdbc.entity; import java.io.Serializable; import lombok.Data; @Data public class User implements Serializable { private static final long serialVersionUID = -1205226416664488559L; private Integer id; private String name; private String sex; }
mapper層
package com.demo.shardingjdbc.mapper; import org.apache.ibatis.annotations.Mapper; import com.demo.shardingjdbc.entity.User; import java.util.List; @Mapper public interface UserMapper { Integer addUser(User user); List<User> list(); }
mybatis配置檔案mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.demo.shardingjdbc.entity"/> </typeAliases> <mappers> <mapper resource="META-INF/mappers/User.xml"/> </mappers> </configuration>
user.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.demo.shardingjdbc.mapper.UserMapper"> <resultMap id="baseResultMap" type="com.demo.shardingjdbc.entity.User"> <result column="id" property="id" jdbcType="INTEGER" /> <result column="name" property="name" jdbcType="VARCHAR" /> <result column="sex" property="sex" jdbcType="VARCHAR" /> </resultMap> <insert id="addUser" parameterType="com.demo.shardingjdbc.entity.User"> INSERT INTO t_user ( id, name, sex ) VALUES ( #{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{sex,jdbcType=VARCHAR} ) </insert> <select id="list" resultMap="baseResultMap"> SELECT u.* FROM t_user u order by u.id </select> </mapper>
5、service層
package com.demo.shardingjdbc.service.impl; import com.demo.shardingjdbc.entity.User; import com.demo.shardingjdbc.mapper.UserMapper; import com.demo.shardingjdbc.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public Integer addUser(User user) { // 強制路由主庫 return userMapper.addUser(user); } @Override public List<User> list() { return userMapper.list(); } }
6、controller層
package com.demo.shardingjdbc.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.demo.shardingjdbc.entity.User; import com.demo.shardingjdbc.service.UserService; import lombok.extern.slf4j.Slf4j; @RestController @Slf4j public class UserController { @Autowired private UserService userService; @GetMapping("/users") public Object list() { return userService.list(); } @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.addUser(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/users,可以查詢資料庫中四個表中的所有資料。可見Sharding-JDBC在插入資料的時候,根據資料分庫分表策略,將資料儲存在不同庫不同表中,查詢時將資料庫從多個表中查詢並聚合。