sharding‐jdbc之分库分表(mysql主从同步的数据库安装和使用)

水平分表

创建基础工程..

引入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=56081spring.application.name = sharding-jdbc-simple-demoserver.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = truespring.main.allow-bean-definition-overriding = truemybatis.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 = trueswagger.enable = truelogging.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 {@AutowiredOrderDao orderDao;@Testpublic void testInsertOrder(){for(int i=1;i<20;i++){orderDao.insertOrder(new BigDecimal(i),1L,"SUCCESS");}}//    @Testpublic 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=56081spring.application.name = sharding-jdbc-simple-demoserver.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = truespring.main.allow-bean-definition-overriding = truemybatis.configuration.map-underscore-to-camel-case = true#sharding-jdbc分片规则配置
#数据源
spring.shardingsphere.datasource.names = m1,m2spring.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 = trueswagger.enable = truelogging.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);
}
 @Testpublic 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库(从库)

    @Testpublic 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);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/795997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaWeb】Day36.MySQL概述——数据库设计-DDL(三)

查询 关于表结构的查询操作&#xff0c;工作中一般都是直接基于图形化界面操作。 1.查询当前数据库所有表 2.查看指定表结构 3.查询指定表的建表语句 注意&#xff1a;23版的点击导航中的转到DDL 修改 关于表结构的修改操作&#xff0c;一般也是直接基于图形化界面操作。 添…

智能感应门改造工程

今天记录一下物联网专业学的工程步骤及实施过程 智能感应门改造工程 1 规划设计1.1 项目设备清单1.2项目接线图 软件设计信号流 设备安装与调试工程函数 验收 1 规划设计 1.1 项目设备清单 1.2项目接线图 软件设计 信号流 设备安装与调试 工程函数 工程界面: using System; …

【STM32】存储器和位带映射(bit band mapping)

文章目录 0 前言1 关于地址和存储器2 STM32内部存储器3 位带映射&#xff08;bit band mapping&#xff09;4 扩展&#xff1a;IAP 0 前言 最近在研究stm32标准库&#xff0c;对使用宏定义实现位操作的函数非常感兴趣&#xff0c;简单的一句PAout(1) 0;就能实现某个引脚电平的…

Linux离线安装python3(源码编译)

1、下载python包 下载python3.9.6的源码包 python下载 下载后&#xff0c;解压&#xff0c;目录如下&#xff1a; -rw-------. 1 root root 1454 Aug 26 2023 anaconda-ks.cfg -rw-r--r--. 1 root root 25640094 Apr 4 21:52 Python-3.9.6.tgz drwxrwxr…

前端三剑客 —— JavaScript (第一天)

目录 回顾内容 1.弹性布局 2.网格布局 JavaScript 概述 发展 浏览器 什么是Javascript JavaScript 能干什么 JavaScript需要的环境 JavaScript初体验 基本数据 JS书写方式 行内JS 页面JS 外部JS 1&#xff09;创建外部JS文件 2&#xff09;编写页面 对话框 警…

ubuntu-server部署hive-part2-安装hadoop

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 安装hadoop ​​​​​​下载上传 下载地址 https://archive.apache.org/dist/hadoop/common/hadoop-3.3.4/ 以root用…

simulink的硬件支持下,串口发送的模型,stm32f407的串口程序调试错误

串口调试助手能接收到数据&#xff0c;为何是8个数据&#xff1f;如之奈何&#xff1f; 参考文章&#xff1a; STM32CubeMxMATLAB Simulink串口输出实验_用stm32cubemx生成的串口都是输出-CSDN博客根据 该文章发送字符串 hello&#xff0c;发送数量为5&#xff0c;接收也是he…

【PyQt5篇】多线程

文章目录 &#x1f354;使用QtDesigner进行设计&#x1f6f8;实现多线程&#x1f339;效果&#x1f50e;原因 &#x1f354;使用QtDesigner进行设计 对应的代码btn.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0">&l…

边界值设计测试用例

​ 边界值分析法&#xff08;Boundary Value Analysis&#xff0c;BVA&#xff09;的测试用例来自于等价类的边界&#xff0c;是等价类划分法的补充。根据边界值划分法&#xff0c;等价类分析法中的测试数据不是选取等价类中的典型值或任意值&#xff0c;而是应当选取正好等于、…

C++语言学习(三)——内联函数、auto、for循环、nullptr

1. 内联函数 &#xff08;1&#xff09;概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调 用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 内联函数是一种编译器指令&#xff0c;用于告诉编译器…

Web3 革命:揭示区块链技术的全新应用

随着数字化时代的不断发展&#xff0c;区块链技术作为一项颠覆性的创新正在改变着我们的世界。而在这一技术的进步中&#xff0c;Web3正逐渐崭露头角&#xff0c;为区块链技术的应用带来了全新的可能性。本文将探讨Web3革命所揭示的区块链技术全新应用&#xff0c;并展望其未来…

Redis从入门到精通(四)Redis实战(一)短信登录

文章目录 前言第4章 Redis实战4.1 短信登录4.1.1 基于session实现短信登录4.1.1.1 短信登录逻辑梳理4.1.1.2 创建测试项目4.1.1.3 实现发送短信验证码功能4.1.1.4 实现用户登录功能4.1.1.5 实现登录拦截功能4.1.1.6 session共享问题 4.1.2 基于Redis实现短信登录4.1.2.1 Key-Va…

顺子日期(结果填空)

为了解决这个问题&#xff0c;我们需要遍历2022年的每一天&#xff0c;并检查日期的每一位数字以查找顺子。下面是一个Java程序&#xff0c;用于计算2022年中的顺子日期数量&#xff1a; public class Main {public static void main(String[] args) {int count 0; for (int…

[StartingPoint][Tier0]Preignition

Task 1 Directory Brute-forcing is a technique used to check a lot of paths on a web server to find hidden pages. Which is another name for this? (i) Local File Inclusion, (ii) dir busting, (iii) hash cracking. (目录暴力破解是一种用于检查 Web 服务器上的大…

leetcode代码记录(有效的字母异位词

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断它们是不是一组变位词&#xff08;字母异位词&#xff09;。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同且字符顺序…

【简单讲解下epoll】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

循环神经网络:揭秘长期记忆的魔法之源

在人工智能和机器学习领域&#xff0c;循环神经网络&#xff08;Recurrent Neural Networks&#xff0c;简称RNN&#xff09;以其独特的架构和机制&#xff0c;在处理序列数据方面展现出了强大的能力。特别值得一提的是&#xff0c;RNN能够学习到长期的记忆&#xff0c;这使得它…

ubuntu-server部署hive-part1-安装jdk

参照 https://blog.csdn.net/qq_41946216/article/details/134345137 操作系统版本&#xff1a;ubuntu-server-22.04.3 虚拟机&#xff1a;virtualbox7.0 安装jdk 上传解压 以root用户&#xff0c;将jdk上传至/opt目录下 tar zxvf jdk-8u271-linux-x64.tar.gz 配置环境变量…

网址打包微信小程序源码 wap转微信小程序 网站转小程序源码 网址转小程序开发

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 我们都知道微信小程序是无法直接打开网址的。 这个小程序源码提供了一种将网址直接打包成微信小程序的方法&#xff0c; 使得用户可以在微信小程序中直接访问这些网址内容。 这个源码没有进行加…

律所如何做好内容运营,提升品牌影响力

近年来&#xff0c;随着品牌推广方式的改变&#xff0c;中国律所也开始关注内容营销&#xff0c;期待能够凭借内容营销增强影响力。今天&#xff0c;媒介盒子就从内容传播的逻辑出发&#xff0c;和大家聊聊律所如何做好内容运营&#xff0c;提升品牌影响力。 一、品牌形象管理 …