原文链接:https://blog.csdn.net/lsqingfeng/article/details/110425971
Sharding JDBC目录
一、Sharding JDBC简介
二、环境准备
环境准备:
本次案例采用springboot和mybatis-plus进行演示,具体版本如下:
首先我们执行一下初始化的sql,创建几张表,然后使用mybatis-plus自动生成所需实体和mapper
1. 初始化sql
CREATE database ds0;
use ds0;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_address
-- ----------------------------
DROP TABLE IF EXISTS `t_address`;
CREATE TABLE `t_address` (
`address_id` bigint(20) NOT NULL,
`address_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`address_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=532651227377807361 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_1
-- ----------------------------
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_2
-- ----------------------------
DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_3
-- ----------------------------
DROP TABLE IF EXISTS `t_order_3`;
CREATE TABLE `t_order_3` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_4
-- ----------------------------
DROP TABLE IF EXISTS `t_order_4`;
CREATE TABLE `t_order_4` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_item
-- ----------------------------
DROP TABLE IF EXISTS `t_order_item`;
CREATE TABLE `t_order_item` (
`order_item_id` bigint(20) NOT NULL,
`order_id` bigint(20) DEFAULT NULL,
`user_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`user_id` bigint(20) NOT NULL,
`user_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;
-- ------------第二个库------------------
CREATE database ds1;
use ds1;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_address
-- ----------------------------
DROP TABLE IF EXISTS `t_address`;
CREATE TABLE `t_address` (
`address_id` bigint(20) NOT NULL,
`address_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`address_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=532651227377807361 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_1
-- ----------------------------
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_2
-- ----------------------------
DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_3
-- ----------------------------
DROP TABLE IF EXISTS `t_order_3`;
CREATE TABLE `t_order_3` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_4
-- ----------------------------
DROP TABLE IF EXISTS `t_order_4`;
CREATE TABLE `t_order_4` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`order_code` varchar(255) DEFAULT NULL,
`address_id` varchar(255) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_order_item
-- ----------------------------
DROP TABLE IF EXISTS `t_order_item`;
CREATE TABLE `t_order_item` (
`order_item_id` bigint(20) NOT NULL,
`order_id` bigint(20) DEFAULT NULL,
`user_id` bigint(20) DEFAULT NULL,
PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for t_user
-- ----------------------------
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`user_id` bigint(20) NOT NULL,
`user_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;
2. 项目结构
其中 bz模块,是用来存放mybatis-plus生成的实体,mapper等文件的, parent模块是管理依赖的,用于其他模块继承的,剩下的几个模块,是分表演示inline策略模式和standard策略模式实现分库分表的。 两个策略都分别给出了yml配置方式和java config配置方式。
3. parent依赖
<?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">
<parent>
<artifactId>shardingjdbc-sample</artifactId>
<groupId>cn.cestc</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>sharding-parent</artifactId>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<spring.boot.version>2.2.5.RELEASE</spring.boot.version>
<action.version>1.0.0</action.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<lombok.version>1.18.8</lombok.version>
<mybatis-plus.version>3.3.1.tmp</mybatis-plus.version>
<mysql.connector.version>8.0.17</mysql.connector.version>
<modelmapper.version>2.3.0</modelmapper.version>
<shardingsphere.version>4.1.1</shardingsphere.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- shardingsphere -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
<!-- for spring namespace -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>${shardingsphere.version}</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<!--编译打包生成源码文档需要的plugins-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!--spring-boot web 项目打jar包插件(jar包里面包含依赖的jar)-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
项目脚手架代码已上传到git: https://github.com/lsqingfeng/sharding-staging.git
这里边只是一个架子,还没有分库分表的实现
好了这几步准备好之后,就可以开始我们的实战了,这一步大家只需要准备好依赖,parent,biz模块即可。后边我们会逐个演示 inline-yml, inline-java, stardard-yml, stard-java 两个策略,两个配置方式的实现。
三、shardingJdbc专题系列(三)之Inline策略分库
1. 需求分析
我们采用最简单的 inline行内表达式策略,通过yml文件中几行简单的配置,来实现一个简单的分库操作。分库的策略是这样的,我们向订单表中插入10条数据,订单表中有订单id和用户id, 订单id我们采用雪花id的生成算法,用户id采用自增的方式,我们又两个库,ds0和ds1, 然后 userId%2, 匹配到不同库中,比如userId是1就保存到ds1库中,userId是2就保存到ds0库中,关于数据库结构,请参看上篇文章,已经给出了sql语句。两个库中都有一个order表。我们通过插入数据,观察效果。
2. 搭建步骤
首先我们创建一个项目module, sharding-inline-yml, (如果已经下载我上篇文章中的脚手架,这个模块已经建好了),依赖sharding-biz模块(该模块是mybatis-plus生成的增删改查), 接下来一步一步来。
添加配置文件
首先添加一个application.yml
server:
port: 9991
spring:
profiles:
active: db
在添加一个配置文件 application-db.yml, (主要是为了后边再加一个application-table.yml演示分表)
# 分库
spring:
shardingsphere:
datasource: #数据源配置
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
sharding: #分片逻辑
default-database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds$->{user_id % 2}
binding-tables: t_order,t_order_item
broadcast-tables: t_user
tables: #表逻辑
t_order:
actual-data-nodes: ds$->{0..1}.t_order
key-generator:
column: order_id
type: SNOWFLAKE
props:
worker:
id: 10
t_order_item:
actual-data-nodes: ds$->{0..1}.t_order_item
key-generator:
column: order_item_id
type: SNOWFLAKE
props:
worker:
id: 12
添加Mybatis-plus配置类和启动主类,
接下来就可以测试了:
package cn.cestc.inline.controller;
import cn.cestc.biz.entity.Order;
import cn.cestc.biz.entity.User;
import cn.cestc.biz.service.AddressService;
import cn.cestc.biz.service.OrderItemService;
import cn.cestc.biz.service.OrderService;
import cn.cestc.biz.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
/**
* @className: TestController
* @description:
* @author: sh.Liu
* @date: 2020-11-15 11:54
*/
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
private final UserService userService;
private final OrderService orderService;
private final OrderItemService orderItemService;
private final AddressService addressService;
public TestController(UserService userService, OrderService orderService, OrderItemService orderItemService, AddressService addressService) {
this.userService = userService;
this.orderService = orderService;
this.orderItemService = orderItemService;
this.addressService = addressService;
}
@RequestMapping("/user")
public String testUser(){
for (int i=1;i<=10; i++) {
User user = new User();
user.setUserId(Long.valueOf(i));
user.setUserName("张三" + i);
userService.save(user);
}
return "sucess";
}
@RequestMapping("/order")
public String testOrder(){
for (int i=1;i<=10; i++) {
Order order = new Order();
order.setUserId(Long.valueOf(i));
order.setOrderCode("acb"+ i);
order.setAddressId(String.valueOf(i));
orderService.save(order);
}
return "sucess";
}
@RequestMapping("/listOrder")
public Object testListOrder(){
List<Order> list = orderService.list(new LambdaQueryWrapper<Order>().in(Order::getUserId, Arrays.asList(1,2,3,4,5)).orderByAsc(Order::getUserId));
return list;
}
}
浏览器调用 localhost:9991/test/order, 查看Order表,发现
就这样数据就根据userId的值分散到了不同的库中。
3. 配置分析
那么这个规则是如何生效的呢,其实先秒尽在配置文件当中:
最关键的就是图上的三个红框。
首先配置两个数据源,ds0,ds1,
然后配置的是分库策略: 分片列是 user_id, 就是根据这列数据做分片, 算法表达式:
ds$->{user_id % 2} ,这个应该比较好理解,根据user_id 对2取余结果,计算存入到那个库中,
t_order表的真实表,
ds$->{0..1}.t_order。
存储没问题了之后,也可以测试一下查询,通过查询列表看得到的结果。 要注意,只支持 = 和 in
四、shardingJdbc专题系列(四)之Inline策略分表
上篇文章我们演示了使用sharding-jdbc进行分库操作的一个小案例, 采用的是inline模式,也就是在yml配置文件中,通过配置分片算法表达式,来进行分片,也简单体验了一下。其实相对来讲还是比较简单的,这些配置也不用背下来,大家只要做好笔记,用的时候,能够根据自己的业务进行套用就行了。当然如果怕记不住,欢迎关注我,或者收藏我的文章,用的时候过来翻翻就可以了。
那么本篇文章我们接着上篇文章继续,来演示一下更常用的分表操作。为什么说分表更常用呢,因为一旦跨库,就需要解决分布式事务的问题,所以很多人不想徒增麻烦,甚至是分库后,可能导致的唯一id一致等问题,都是很头疼的。接下来进入分表。分表一般都是在一个库里进行操作。会有结构一致的表, 比如 t_order_1, t_order_2, 通过第一节的概念我们提到过,这些表叫做真实表, 他们结构一致, t_order是他们的逻辑表,当然逻辑表是可以不存在的。只是真实表结构的一个总称,并且我们进行查询的时候,只需要写 select * from t_order就行了, shardingJdbc会自动帮助我们去真实表中查询,并整合结果。
好的环境搭建:
我们还是在上篇文章的项目下继续展开,上篇文章已经给出了代码的脚手架。下载下来按照的步骤执行,就能够运行起来。
首先我们还是在 sharding-inline-yml的module下执行, 在resources 资源目录下重新添加一个配置文件 application-table.yml, 用于添加分表的配置,内容如下:
#分表
spring:
shardingsphere:
datasource: #数据源配置
names: ds0
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
# 分表配置
sharding:
default-table-strategy:
inline:
sharding-column: user_id
algorithm-expression: t_order_${user_id % 4 + 1}
# 配置广播表
broadcast-tables: t_user
binding-tables: t_order,t_order_item
tables:
t_order:
actual-data-nodes: ds0.t_order_$->{1..4}
key-generator:
column: order_id
type: SNOWFLAKE
props:
worker:
id: 123
table-strategy:
inline:
sharding-column: user_id
algorithm-expression: t_order_${user_id % 4 + 1}
这里可以看到,这次的数据源,我们只用了一个ds0,相当于只在这一个库中操作即可。主要看分表的配置: 首先是有一个默认的分表策略,还配置了一个广播表,和绑定表。广播表其实主要在分库的时候用,被配置成广播表的表,在插入的时候,会在多个分片(库)中同时插入一份。 比如一些字段表,或者配置表,在跨库时关联操作不方便,配置成广播表,各个库里就会都有一份内容完成一样。
tables下面就是对表的操作。不同的表可以配置不同的分片算法,建议所以需要分片的表,都要在下面配置,不分片的都配置成广播表。
我们这里只配了t_order表,当然还可以继续配置其他表。我们表的怎是节点表达式是: ds0.t_order_$->{1…4}
代表真实表为 t_order_1, t_order_2, t_order_3, t_order4, 那么到底是存到哪张表里呢,有下面的table-strategy, 表策略决定: 表策略首先给出inline, 代表使用inline策略:
分片列为: user_id
分片算法表达式: t_order_${user_id %4 +1} 根据user_id 对4取模后加1, 结果肯定格式1-4,来计算到底插入哪张表中。
好了,但是别忘了,在application.yml配置文件中指定使用application-table.yml的配置文件。
spring:
profiles:
active: table
然后继续执行主类,启动程序。 访问: localhost:9991/test/order, 向order中插入10条数据,user_id 从1到10;去库中观察结果,此时所有插入的数据都在ds0库中,分布在不同的表中;
好了很简单的分表就这样完成了。 你get到了么。
说一下大家执行的流程,只需要下载我篇文章的脚手架,然后导入数据库脚本,把配置文件按照文章中的步骤粘贴进去,就可以直接运行了。无需任何其他操作。
另外结合这两篇文章,大家可以测试一下同时分库分表应该怎么做,其实就是配置一下表达式就行了,把两篇文章结合一下即可。
好了这篇文章就到这了,下篇文章我们讲下,如果不想使用yml配置文件,想用java config的方式实现上述功能,代码应该怎么写。
五、shardingJdbc专题系列(五)之Inline策略 java config 实现方式
前面几篇文章我们都是通过yml配置文件的方式,简单实现了 inline模式下的分库分表。 通过yml的方式,我们需要在配置文件中配置数据源和分库分表的策略表达式。那么如果我不想在配置文件中写如此冗长的配置,能否采用java config 的方式实现呢。肯定是可以的。
本篇文章我们就来介绍通过java config的方式来重新实现inline模式下的分库分表。本次代码案例我们在git脚手架里的 sharding-inline-java 的module下进行。(git地址参看第一篇文章)
首先还是先依赖 sharding-biz, 主要是配置文件。
首先在config包下创建 MybatisPlusConfig 配置类,内容如下; (注意:有一个ConditionOnBean注解,用来限制类的加载顺序,防止出错)
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "cn.cestc.biz.mapper")
@ConditionalOnBean(value= DataSource.class)
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setLimit(-1);
return paginationInterceptor;
}
}
第二步,添加一个 shardingJdbc的配置类,用来替换原来的yml
import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.apache.shardingsphere.spring.boot.util.DataSourceUtil;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;
/**
* @className: ShardingDataSourceConfiguration
* @description:
* @author: sh.Liu
* @date: 2020-11-03 19:23
*/
@Configuration
@MapperScan(basePackages = "cn.cestc.biz.mapper")
public class ShardingDataSourceConfiguration {
@Bean("shardingDataSource")
public DataSource getShardingDataSource() throws SQLException, ReflectiveOperationException {
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
// 广播表
List<String> broadcastTables = new LinkedList<>();
broadcastTables.add("t_user");
broadcastTables.add("t_address");
shardingRuleConfig.setBroadcastTables(broadcastTables);
// 默认策略
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds0"));
shardingRuleConfig.setDefaultTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "t_order_${user_id % 4 + 1}"));
// 获取user表的分片规则配置
TableRuleConfiguration userInfoTableRuleConfiguration = getUserInfoTableRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(userInfoTableRuleConfiguration);
Properties props = new Properties();
props.put("sql.show", "true");
return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, props);
}
/**
* 配置真实数据源
* @return 数据源map
*/
private Map<String, DataSource> createDataSourceMap() throws ReflectiveOperationException {
Map<String, DataSource> dataSourceMap = new HashMap<>();
Map<String, Object> dataSourceProperties = new HashMap<>();
dataSourceProperties.put("DriverClassName", "com.mysql.jdbc.Driver");
dataSourceProperties.put("jdbcUrl", "jdbc:mysql://localhost:3306/ds0?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8");
dataSourceProperties.put("username", "root");
dataSourceProperties.put("password", "root");
DataSource dataSource1 = DataSourceUtil.getDataSource("com.zaxxer.hikari.HikariDataSource", dataSourceProperties);
Map<String, Object> dataSourceProperties2 = new HashMap<>();
dataSourceProperties2.put("DriverClassName", "com.mysql.jdbc.Driver");
dataSourceProperties2.put("jdbcUrl", "jdbc:mysql://localhost:3306/ds1?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8");
dataSourceProperties2.put("username", "root");
dataSourceProperties2.put("password", "root");
DataSource dataSource2 = DataSourceUtil.getDataSource("com.zaxxer.hikari.HikariDataSource", dataSourceProperties2);
dataSourceMap.put("ds0",dataSource1);
dataSourceMap.put("ds1",dataSource2);
return dataSourceMap;
}
/**
* 配置user表的分片规则
*
* @return ser表的分片规则配置对象
*/
private TableRuleConfiguration getUserInfoTableRuleConfiguration() {
// 为user表配置数据节点
TableRuleConfiguration ruleConfiguration = new TableRuleConfiguration("t_order", "ds0.t_order_$->{1..4}");
// 设置分片键
String shardingKey = "user_id";
// 为user表配置分库分片策略及分片算法
ruleConfiguration.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration(shardingKey, "ds$->{user_id % 2}"));
// 为user表配置分表分片策略及分片算法
ruleConfiguration.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration(shardingKey, "t_order_${user_id % 4 + 1}"));
ruleConfiguration.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_id"));
return ruleConfiguration;
}
}
这个类中,配置了数据源的集合,同时在getUserInfoTableRuleConfiguration 方法中配置了order表的分库分表策略,和之前yml文件中的配置都是对应的,如果有多个表,添加多个方法,在getShardingDataSource 方法中添加(add) 多个策略即可。
最关键的是启动类,需要排除一个类 @SpringBootApplication(exclude = {SpringBootConfiguration.class}), 注意的是 SpringBootConfiguration要选择的是 shardingjdbc包下面的这个类:代码如下
import org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @className: ShardingInlineJavaApplication
* @description:
* @author: sh.Liu
* @date: 2020-11-15 10:57
*/
@SpringBootApplication(exclude = {SpringBootConfiguration.class})
public class ShardingInlineJavaApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingInlineJavaApplication.class, args);
}
}
好了,万事具备,接下来写一个测试的Controller, 测试一下分库分表的策略是否生效即可。
关于inline模式的分库分表到这里就告一段落了,在这一部分中,我们详细介绍了inline模式如何分库,如何分表,以及如何使用java config 实现。 下一部分我们重点研究下一种策略, standard标准策略的分库分表。