水平分表
创建基础工程..
引入sharding‐jdbc的maven依赖包 注意需要数据库连接池等依赖
<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>sharding-jdbc-spring-boot-starter</artifactId> <version>4.0.0-RC1</version> </dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.16</version> </dependency>
表结构
-- 创建库
CREATE DATABASE `order_db` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';-- 创建表1
DROP TABLE IF EXISTS `t_order_1`;
CREATE TABLE `t_order_1` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`price` decimal(10,2) NOT NULL COMMENT '订单价格',
`user_id` bigint(20) NOT NULL COMMENT '下单用户id',
`status` varchar(50) NOT NULL COMMENT '订单状态',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- 创建表2
DROP TABLE IF EXISTS `t_order_2`;
CREATE TABLE `t_order_2` (
`order_id` bigint(20) NOT NULL COMMENT '订单id',
`price` decimal(10,2) NOT NULL COMMENT '订单价格',
`user_id` bigint(20) NOT NULL COMMENT '下单用户id',
`status` varchar(50) NOT NULL COMMENT '订单状态',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
配置文件
server.port=56081 spring.application.name = sharding-jdbc-simple-demo server.servlet.context-path = /sharding-jdbc-simple-demo spring.http.encoding.enabled = true spring.http.encoding.charset = UTF-8 spring.http.encoding.force = true spring.main.allow-bean-definition-overriding = true mybatis.configuration.map-underscore-to-camel-case = true #sharding-jdbc分片规则配置 #数据源 spring.shardingsphere.datasource.names = m1 # 指定数据源 m1 对应的数据库信息 spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3306/order_db?useUnicode=true spring.shardingsphere.datasource.m1.username = root spring.shardingsphere.datasource.m1.password = root # 指定 t_order 表的数据分布情况,t_order是表的前缀, 配置数据节点 m1.t_order_1 => t_order_1 ,m1.t_order_2 => t_order_2 # 分多少表 分片键 就到多少$->{1..10} spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m1.t_order_$->{1..3} # 指定t_order表的主键生成策略为 雪花算法 SNOWFLAKE spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE # 指定t_order表的分片策略,分片策略包括分片键和分片算法; # order_id:主键。计算表的后缀 :order_id_?; $->{order_id % 2 + 1} = 偶数0 + 1 = 1 即 order_id_1 ; $->{order_id % 2 + 1} = 奇数 1 + 1 = 2 即 order_id_2 # 分 几 个表 分片键就除以几 {order_id % 10 + 1} spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 3 + 1} # 打开sql输出日志 spring.shardingsphere.props.sql.show = true swagger.enable = true logging.level.root = info logging.level.org.springframework.web = info logging.level.com.itheima.dbsharding = debug logging.level.druid.sql = debug
编写插入语句
import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.List; import java.util.Map; /** * Created by Administrator. */ @Mapper @Component public interface OrderDao { /** * 插入订单 * @param price * @param userId * @param status * @return */ @Insert("insert into t_order(price,user_id,status)values(#{price},#{userId},#{status})") int insertOrder(@Param("price")BigDecimal price,@Param("userId")Long userId,@Param("status")String status); /** * 根据id列表查询订单 * @param orderIds * @return */ @Select("<script>" + "select" + " * " + " from t_order t " + " where t.order_id in " + " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" + " #{id} " + " </foreach>" + "</script>") List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds); }
单元测试
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author Administrator * @version 1.0 **/ @RunWith(SpringRunner.class) @SpringBootTest(classes = {ShardingJdbcSimpleBootstrap.class}) public class OrderDaoTest { @Autowired OrderDao orderDao; @Test public void testInsertOrder(){ for(int i=1;i<20;i++){ orderDao.insertOrder(new BigDecimal(i),1L,"SUCCESS"); } } // @Test public void testSelectOrderbyIds(){ List<Long> ids = new ArrayList<>(); ids.add(373897739357913088L); ids.add(373897037306920961L); List<Map> maps = orderDao.selectOrderbyIds(ids); System.out.println(maps); } }
数据库 表1 插入数据
表2
流程分析
通过日志分析,Sharding-JDBC在拿到用户要执行的sql之后干了哪些事儿:
(1)解析sql,获取片键值,在本例中是order_id
(2)Sharding-JDBC通过规则配置 t_order_$->{order_id % 2 + 1},知道了当order_id为偶数时,应该往t_order_1表插数据,为奇数时,往t_order_2插数据。
(3)于是Sharding-JDBC根据order_id的值改写sql语句,改写后的SQL语句是真实所要执行的SQL语句。
(4)执行改写后的真实sql语句
(5)将所有真正执行sql的结果进行汇总合并,返回。
分片策略
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。内置的分片策略大致可分为尾数取模、哈希、范围、标签、时间等。由用户方配置的分片策略则更加灵活,常用的使用行表达式配置分片策略,它采用Groovy表达式表示,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为 t_user_0 到 t_user_7 。
SQL解析
当Sharding-JDBC接受到一条SQL语句时,会陆续执行 SQL解析 => 查询优化 => SQL路由 => SQL改写 => SQL执行 =>结果归并 ,最终返回执行结果。
SQL解析过程分为词法解析和语法解析。 词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字,表达式,字面量和操作符。 再使用语法解析器将SQL转换为抽象语法树。
例如
SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18
解析之后的为抽象语法树见下图:
SQL路由
SQL路由就是把针对逻辑表的数据操作映射到对数据结点操作的过程。
根据解析上下文匹配数据库和表的分片策略,并生成路由路径。 对于携带分片键的SQL,根据分片键操作符不同可以划分为单片路由(分片键的操作符是等号)、多片路由(分片键的操作符是IN)和范围路由(分片键的操作符是BETWEEN),不携带分片键的SQL则采用广播路由。根据分片键进行路由的场景可分为直接路由、标准路由、笛卡尔路由等
标准路由
笛卡尔路由
全库表路由
SQL改写
工程师面向逻辑表书写的SQL,并不能够直接在真实的数据库中执行,SQL改写用于将逻辑SQL改写为在真实数据库中可以正确执行的SQL
如一个简单的例子,若逻辑SQL为:
SELECT order_id FROM t_order WHERE order_id=1;
假设该SQL配置分片键order_id,并且order_id=1的情况,将路由至分片表1。那么改写之后的SQL应该为:
SELECT order_id FROM t_order_1 WHERE order_id=1;
SQL执行
Sharding-JDBC采用一套自动化的执行引擎,负责将路由和改写完成之后的真实SQL安全且高效发送到底层数据源执行。 它不是简单地将SQL通过JDBC直接发送至数据源执行;也并非直接将执行请求放入线程池去并发执行。它更关注平衡数据源连接创建以及内存占用所产生的消耗,以及最大限度地合理利用并发等问题。 执行引擎的目标是自动化的平衡资源控制与执行效率,他能在以下两种模式自适应切换:
内存限制模式
使用此模式的前提是,Sharding-JDBC对一次操作所耗费的数据库连接数量不做限制。 如果实际执行的SQL需要对某数据库实例中的200张表做操作,则对每张表创建一个新的数据库连接,并通过多线程的方式并发处理,以达成执行效率最大化。
连接限制模式
使用此模式的前提是,Sharding-JDBC严格控制对一次操作所耗费的数据库连接数量。 如果实际执行的SQL需要对某数据库实例中的200张表做操作,那么只会创建唯一的数据库连接,并对其200张表串行处理。 如果一次操作中的分片散落在不同的数据库,仍然采用多线程处理对不同库的操作,但每个库的每次操作仍然只创建一个唯一的数据库连接。
内存限制模式适用于OLAP操作,可以通过放宽对数据库连接的限制提升系统吞吐量; 连接限制模式适用于OLTP操作,OLTP通常带有分片键,会路由到单一的分片,因此严格控制数据库连接,以保证在线系统数据库资源能够被更多的应用所使用,是明智的选择。
结果归并
将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。Sharding-JDBC支持的结果归并从功能上可分为遍历、排序、分组、分页和聚合5种类型,它们是组合而非互斥的关系。
归并引擎的整体结构划分如下图
结果归并从结构划分可分为流式归并、内存归并和装饰者归并。流式归并和内存归并是互斥的,装饰者归并可以在流式归并和内存归并之上做进一步的处理。
内存归并
他是将所有分片结果集的数据都遍历并存储在内存中,再通过统一的分组、排序以及聚合等计算之后,再将其封装成为逐条访问的数据结果集返回。
流式归并
是指每一次从数据库结果集中获取到的数据,都能够通过游标逐条获取的方式返回正确的单条数据,它与数据库原生的返回结果集的方式最为契合
装饰者归并
是对所有的结果集归并进行统一的功能增强,比如归并时需要聚合SUM前,在进行聚合计算前,都会通过内存归并或流式归并查询出结果集。因此,聚合归并是在之前介绍的归并类型之上追加的归并能力,即装饰者模式。
1、每个表先排序
2、从第一个表里面找到最大的,和后边的比较,找到最大值100
3、然后拿第一表的第二大值90去和99、95比较大小, 找到第二大值 99
4、然后拿第二个表的第二大值89和95比较,找到第三大值 95
依次类推.....,一个一个的去比对,就像一个游标
分库
配置文件
server.port=56081 spring.application.name = sharding-jdbc-simple-demo server.servlet.context-path = /sharding-jdbc-simple-demo spring.http.encoding.enabled = true spring.http.encoding.charset = UTF-8 spring.http.encoding.force = true spring.main.allow-bean-definition-overriding = true mybatis.configuration.map-underscore-to-camel-case = true #sharding-jdbc分片规则配置 #数据源 spring.shardingsphere.datasource.names = m1,m2 spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m1.driver‐class‐name = com.mysql.jdbc.Driver spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3306/order_db_1?useUnicode=true spring.shardingsphere.datasource.m1.username = root spring.shardingsphere.datasource.m1.password = root spring.shardingsphere.datasource.m2.type = com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m2.driver‐class‐name = com.mysql.jdbc.Driver spring.shardingsphere.datasource.m2.url = jdbc:mysql://localhost:3306/order_db_2?useUnicode=true spring.shardingsphere.datasource.m2.username = root spring.shardingsphere.datasource.m2.password = root # 分库策略,以user_id为分片键,分片策略为user_id % 2 + 1,user_id为偶数操作m1数据源,否则操作m2。 spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.sharding-column = user_id spring.shardingsphere.sharding.tables.t_order.database-strategy.inline.algorithm-expression =m$->{user_id % 2 + 1 } # 计算表(共多少表) # 指定 t_order 表的数据分布情况,t_order是表的前缀, 配置数据节点 m1.t_order_1,m1.t_order_2,,m1.t_order_3, m2.t_order_1,m2.t_order_2,m2.t_order_3 spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m$->{1..2}.t_order_$->{1..3}#分库策略,如何将一个逻辑表映射到多个数据源 spring.shardingsphere.sharding.tables.<逻辑表名称>.database-strategy.<分片策略>.<分片策略属性名>= #分片策略属性值 #分表策略,如何将一个逻辑表映射为多个实际表 spring.shardingsphere.sharding.tables.<逻辑表名称>.table-strategy.<分片策略>.<分片策略属性名>= #分片策略属性值
# 指定t_order表的主键 order_id 生成策略为 雪花算法 SNOWFLAKE spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE # 计算数据落到哪个表里面 # 指定t_order表的分片策略,分片策略包括分片键:order_id 和 分片算法: t_order_$->{order_id % 3 + 1} # order_id:主键。计算表的后缀 :order_id_?; $->{order_id % 2 + 1} = 偶数0 + 1 = 1 即 order_id_1;$->{order_id % 2 + 1}=奇数 1+1=2 即 order_id_2;分几个表 分片键就除以几 {order_id % 10 + 1} spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 3 + 1} # 打开sql输出日志 spring.shardingsphere.props.sql.show = true swagger.enable = true logging.level.root = info logging.level.org.springframework.web = info logging.level.com.itheima.dbsharding = debug logging.level.druid.sql = debugc
插入数据
/** * 插入订单 * @param price * @param userId * @param status * @return */ @Insert("insert into t_order(price,user_id,status)values(#{price},#{userId},#{status})") int insertOrder(@Param("price")BigDecimal price,@Param("userId")Long userId,@Param("status")String status);
测试插入
@Test public void testInsertOrder(){ for(int i=1;i<=20;i++){ orderDao.insertOrder(new BigDecimal(i),1L,"SUCCESS"); } }
插入数据
测试查询
@Test public void testSelectOrderbyUserAndIds(){ List<Long> ids = new ArrayList<>(); ids.add(982641951578783745L); ids.add(982641951578783746L); ids.add(982641951247433729L); List<Map> maps = orderDao.selectOrderbyUserAndIds(2L,ids); System.out.println(maps); }@Test public void testSelectOrderbyIds(){ List<Long> ids = new ArrayList<>(); ids.add(982641951578783745L); ids.add(982641951578783746L); ids.add(982641951247433729L); List<Map> maps = orderDao.selectOrderbyIds(ids); System.out.println(maps); }
dao层
/** * 根据id列表查询订单 * @param orderIds * @return */ @Select("<script>" + "select" + " * " + " from t_order t " + " where t.order_id in " + " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" + " #{id} " + " </foreach>" + "</script>") List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds); /** * 根据id列表和用户id查询订单 * @param orderIds * @return */ @Select("<script>" + "select" + " * " + " from t_order t " + " where t.order_id in " + " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" + " #{id} " + " </foreach>" + " and user_id = #{userId} " + "</script>") List<Map> selectOrderbyUserAndIds(@Param("userId") Long userId,@Param("orderIds") List<Long> orderIds);
Sharding-JDBC支持以下几种分片策略:
不管理分库还是分表,策略基本一样。
standard:标准分片策略,
对应StandardShardingStrategy。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。PreciseShardingAlgorithm是必选的,用于处理=和IN的分片。RangeShardingAlgorithm是可选的,用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
complex:符合分片策略
对应ComplexShardingStrategy。复合分片策略。提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装,而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
inline:行表达式分片策略
对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为 t_user_0 到t_user_7 。
hint:Hint分片策
对应HintShardingStrategy。通过Hint而非SQL解析的方式分片的策略。对于分片字段非SQL决定,而由其他外置条件决定的场景,可使用SQL Hint灵活的注入分片字段。例:内部系统,按照员工登录主键分库,而数据库中并无此字段。SQL Hint支持通过Java API和SQL注释(待实现)两种方式使用。
none:不分片策略
对应NoneShardingStrategy。不分片的策略。
公共表
公共表属于系统中数据量较小,变动少,而且属于高频联合查询的依赖表。参数表、数据字典表等属于此类型。可以将这类表在每个数据库都保存一份,所有更新操作都同时发送到所有分库执行。接下来看一下如何使用Sharding-JDBC实现公共表。
(1)创建数据库
分别在user_db、order_db_1、order_db_2中创建t_dict表:
CREATE TABLE `t_dict` (
`dict_id` BIGINT ( 20 ) NOT NULL COMMENT '字典id',
`type` VARCHAR ( 50 ) CHARACTER
SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典类型',
`code` VARCHAR ( 50 ) CHARACTER
SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典编码',
`value` VARCHAR ( 50 ) CHARACTER
SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典值',
PRIMARY KEY ( `dict_id` ) USING BTREE
) ENGINE = INNODB CHARACTER
SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
配置文件
# 指定t_dict为公共表 spring.shardingsphere.sharding.broadcast‐tables=t_dict
添加字典
/** * 新增字典 * @param type 字典类型 * @param code 字典编码 * @param value 字典值 * @return */ @Insert("insert into t_dict(dict_id,type,code,value) value(#{dictId},#{type},#{code},#{value})") int insertDict(@Param("dictId") Long dictId, @Param("type") String type, @Param("code")String code, @Param("value")String value);
测试
@Test public void testInsertDict(){ dictDao.insertDict(3L,"user_type","2","超级管理员"); dictDao.insertDict(4L,"user_type","3","二级管理员"); }
删除
@Test public void testDeleteDict(){ dictDao.deleteDict(3L); dictDao.deleteDict(4L); }/** * 删除字典 * @param dictId 字典id * @return */ @Delete("delete from t_dict where dict_id = #{dictId}") int deleteDict(@Param("dictId") Long dictId);
表数据都删除了
关联查询
@Test public void testSelectUserInfobyIds(){ List<Long> userIds = new ArrayList<>(); userIds.add(1L); userIds.add(2L); List<Map> users = userDao.selectUserInfobyIds(userIds); System.out.println(users); }/** * 根据id列表查询多个用户 用户和字典关联 * @param userIds 用户id列表 * @return */ @Select({"<script>", " select", " * ", " from t_user t ,t_dict b", " where t.user_type = b.code and t.user_id in", "<foreach collection='userIds' item='id' open='(' separator=',' close=')'>", "#{id}", "</foreach>", "</script>" }) List<Map> selectUserInfobyIds(@Param("userIds") List<Long> userIds);
主从复制数据库安装
刚开始只有一个
一、复制一份之前安装的安装目录,并修改名称为 mysql-5.7.20-winx64-s1
修改配置文件 my.ini
修改端口号和目录
然后使用安装脚本
管理员运行cmd(可能不行)
mysqld install mysqls1 --defaults-file="D:\RuanJianKaiFa\mysql\mysql-5.7.20-winx64-s1\my.ini"
二、或者使用安装脚本命令
D:
cd D:\RuanJianKaiFa\mysql\mysql-5.7.20-winx64-s1\bin
mysqld --initialize-insecure --user=mysqls1
mysqld -install
net start mysql
mysql -u root -p
修改密码脚本命令
D:
cd D:\RuanJianKaiFa\mysql\mysql-5.7.20-winx64-s1\bin
mysqladmin -uroot -p password
安装成功
主库配置
# 主从同步配置
#主库开启日志
log-bin = mysql-bin
#设置服务id,主从不能一致
server-id = 1
#设置需要同步的数据库
binlog-do-db=user_db
#屏蔽系统库同步
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
从库配置
#开启日志 从库配置
log-bin = mysql-bin
#设置服务id,主从不能一致
server-id = 2
#设置需要同步的数据库
replicate_wild_do_table=user_db.%
#屏蔽系统库同步
replicate_wild_ignore_table=mysql.%
replicate_wild_ignore_table=information_schema.%
replicate_wild_ignore_table=performance_schema.%
主库和从库都重启服务
连接从库
三,授权主从复制专用账号
主库操作
主库的用户
执行创建用户的命令 连接主库后执行
-- 授权主备复制专用账号
GRANT REPLICATION SLAVE ON *.* TO 'db_sync' @'%' IDENTIFIED BY 'db_sync';-- 刷新权限
FLUSH PRIVILEGES;
主库创建用户成功
确认位点 记录下文件名以及位点
-- 确认位点 记录下文件名以及位点
show master status;
从库操作
-- 先停止同步
STOP SLAVE;
修改从库指向到主库,使用上一步记录的文件名以及位点
#修改从库指向到主库,使用上一步记录的文件名以及位点
CHANGE MASTER TO
master_host = 'localhost',
master_user = 'db_sync',
master_password = 'db_sync',
master_log_file = 'mysql-bin.000001',
master_log_pos = 154;
执行成功
启动同步
START SLAVE;
-- 查看从库状态Slave_IO_Runing和Slave_SQL_Runing都为Yes说明同步成功,如果不为Yes,请检查error_log,然后排查相关异常。
show slave status
都是yes才行
请注意,主从MySQL下的数据(data)目录下有个文件auto.cnf,文件中定义了uuid,要保证主从数据库实例的uuid不一样,建议直接删除掉,重启服务后将会重新生成。
从库目录找到auto.cnf,由于是从库是复制的主库,这里文件是一样的,里面有一个uuid
将这个文件删除后重启服务,会从新生成此文件
重新生成文件
再次查看 都是yes 了
测试 是否同步成功
添加主库数据,去从库数据,看从库数据是否修改
同步成功
注意 注意 注意
配置的数据库和要同步的库要一样
实现sharding-jdbc读写分离
配置文件
spring.shardingsphere.datasource.names = m0,m1,m2,s0
spring.shardingsphere.datasource.s0.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.s0.driver‐class‐name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.s0.url = jdbc:mysql://localhost:3307/user_db?useUnicode=true
spring.shardingsphere.datasource.s0.username = root
spring.shardingsphere.datasource.s0.password = root
主库从库逻辑数据源定义
#主库 spring.shardingsphere.sharding.master‐slave‐rules.ds0.master-data-source-name=m0 #从库 spring.shardingsphere.sharding.master‐slave‐rules.ds0.slave-data-source-names=s0
t_user分表策略,固定分配至ds0的t_user真实表
# t_user分表策略,固定分配至ds0的t_user真实表 spring.shardingsphere.sharding.tables.t_user.actual-data-nodes = ds0.t_user
测试查询 走的s0库(从库)
@Test public void testSelectUserbyIds(){ List<Long> userIds = new ArrayList<>(); userIds.add(1L); // userIds.add(2L); List<Map> users = userDao.selectUserbyIds(userIds); System.out.println(users); }/** * 根据id列表查询多个用户 * @param userIds 用户id列表 * @return */ @Select({"<script>", " select", " * ", " from t_user t ", " where t.user_id in", "<foreach collection='userIds' item='id' open='(' separator=',' close=')'>", "#{id}", "</foreach>", "</script>" }) List<Map> selectUserbyIds(@Param("userIds") List<Long> userIds);
测试添加 走的m0库(主库)
@Test public void testInsertUser(){ for (int i = 2 ; i<3; i++){ Long id = i + 1L; userDao.insertUser(id,"姓名"+ id ); } }/** * 新增用户 * @param userId 用户id * @param fullname 用户姓名 * @return */ @Insert("insert into t_user(user_id, fullname) value(#{userId},#{fullname})") int insertUser(@Param("userId")Long userId, @Param("fullname")String fullname);