Shardingjdbc完整笔记,数据库中间件,基础入门(狂神)

1.ShardingSphere的三部曲

ShardingSphere的三部曲

  1. ShardingSphere - JDBC ( 可理解为增强版的 JDBC 驱动 )
  2. ShardingSphere - Proxy( sharding-proxy 相当于 mycat,单独一个服务)
  3. ShardingSphere - Sidecar(TODO)

2.搭建MySQL读写分离(Linux安装mysql)

2.1 普通安装mqsql搭建(方式一)

    ## 1.配置mysql扩展源
    rpm -ivh http://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/mysql57-community-release-el7-10.noarch.rpm
    ## 2.yum安装mysql
    yum install mysql-community-server -y
    ## 3.启动mysql,并加入开机自启
    systemctl start mysqld
    systemctl stop mysqld
    systemctl enable mysqld      -- 设置mysql服务开机自启动
    systemctl status mysqld      -- 查看mysql服务启动状态
    ## 4.使用msql初始密码登录数据库
    mysql -uroot -p$(awk '/temporary password/{print $NF}' /var/log/mysqld.log)
    ## 5.修改密码
    -- 降低mysql设置密码的难度(不更改密码需要包含大小写等字符)
    set global validate_password_policy=0;
    set global validate_password_length=1;
    -- 修改密码
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';
    -- 退出mysql服务
    quit;                          
    -- 命令行到登录mysql
    mysql -uroot -proot           
    -- 授权远程登录
    grant all on *.* to root@'%' identified by 'root';
    -- 涮新
    flush privileges;
    ## 6.本地远程连接云服务器
    ## 本地远程连接linux服务器
    注:
      主从复制 --> 从数据库层面说的
      读写分离 --> 代码业务层面说的

Master节点修改配置(master节点的 “/etc/my.cnf”)

①需改配置文件保存二进制文件

 >vim /etc/my.cnf
    ## 找到"[mysqld]"下面复制下面的配置
    [mysqlId]
    ## 唯一id
    server-id=100
    ## 开启二进制日志功能,名字可以随便取
    log-bin=mysql-bin
    ## 复制过滤:不需要备份的数据库(mysql的mysql库一般不需要同步)
    binlog-ignore-db=mysql
    ## 下面的这些配置可以不需要写
    ## 为每个session分配的内存,在事务过程中用来存储二进制日志的缓存
    binlog_cache_size=1M
    ## 主从复制的格式(mixed,statement,row,默认格式是statement)
    binlog_format=mixed

注:配置完需要重启

②mater服务器给slave服务器授权

mysql -uroot -proot
## 授予slave服务器可以同步master服务
grant replication slave,replication client on *.* to 'root'@'slave服务的ip' identified by 'slave服务器的密码'; 
## 刷新
flush privileges;
## 查看mysql现在有哪些用户及对应的ip权限(可以不执行,只是一个查看)
select user,host from mysql.user;

③查询master服务器的binlog文件名和位置

show master status;

Slave节点修改配置(slave节点的 “/etc/my.cnf”)

①需改配置文件保存二进制文件

 >vim /etc/my.cnf
    ## 找到"[mysqld]"下面复制下面的配置
    [mysqlId]
    ## 唯一id
    server-id=102
    ## 开启二进制日志功能,以备slave作为其他slave的master时使用
    log-bin=mysql-slave-bin
    ## relay_log配置中继日志
    relay_log=edu-mysql-relay-bin
    ## 复制过滤:不需要备份的数据库(mysql的mysql库一般不需要同步)
    binlog-ignore-db=mysql
    ## 如果需要同步函数或者存储过程
    log_bin_trust_function_creators=true
    ## 为每个session分配的内存,在事务过程中用来存储二进制日志的缓存
    binlog_cache_size=1M
    ## 主从复制的格式(mixed,statement,row,默认格式是statement)
    binlog_format=mixed
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断
    ## 如:1062错误是指一些主键重复。1032错误是因为主从数据库数据不一致
    slave_skip_errors=1062

注:配置完需要重启

②slave服务器进行关联master服务器

mysql>mysql -uroot -proot
-- "master_log_file""master_log_pos" 在master机上"show master status;"
change master to master_host='master服务器ip',master_user='root',master_password='master密码',master_port=3306,master_log_file='master查到的',master_log_pos=master查到的;

③在slave节点查看主从同步状态

## 启动主从复制
start slave;
## 再查看主从同步状态
show slave status\G;
## 停止复制
stop slave;

主从复制报错

①从服务器没有同步主服务器的数据
②输入主服务器的密码错误

 ## 原因1:复制位置发生改变(这种可能性比较大)
    ## 操作从服务器
    ## 停止复制
    stop slave;
    ## "master_log_file"和"master_log_pos" 在master机上"show master status;"
    change master to master_host='master服务器ip',master_user='root',master_password='master密码',master_port=3306,master_log_file='master查到的',master_log_pos=master查到的;
    ## 启动主从复制
    start slave;
    ## 原因2:更改服务器了
    ## 操作从服务器
    ## 停止复制
    stop slave;
    set global sql_slave_skip_counter=1;
    ## 启动主从复制
    start slave;
    ## 再查看主从同步状态
    show slave status\G;

2.2使用Docker安装mysql(我使用的方式)

注:如果上面安装过了就跳过这一步,我懒得配置,下载也比较麻烦,所以直接使用docker安装的mysql,大家不会docker的可以去看下我的

docker快速入门:https://blog.csdn.net/wang121213145/category_11575654.html?spm=1001.2014.3001.5482
docker中安装mysql并配置主从复制:
[TODO]

3.代码实战读写分离

概述:定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
在这里插入图片描述
在这里插入图片描述

在主数据库创建数据库以及数据库表:
在这里插入图片描述

创建一个springboot项目:
在这里插入图片描述

添加pom依赖:

<groupId>com.xii</groupId>
    <artifactId>shardingjdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shardingjdbc</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <shardingsphere.version>4.0.0-RC1</shardingsphere.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- mysql5.7驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.4</version>
            <scope>runtime</scope>
        </dependency>
        <!-- jsonson处理,服务于jsonutil工具和springmvc的json返回 -->
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-avro</artifactId>
            <version>2.10.0</version>
        </dependency>
        <!-- md5密码加密的时依赖的包 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.11</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>${shardingsphere.version}</version>
        </dependency>
        <!--mybatis-plus整合mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.6</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

application.yml配置

server:
  port: 8999
logging:
  level:
    root: info
spring:
  profiles:
    active: dev
  main:   #允许相同bean名称覆盖
    allow-bean-definition-overriding: true
  application:
    name: shardingsphere-demo
  jackson:
    # 日期进行格式化处理
    date-format: yyyy/MM/dd HH:mm:ss
    # 解决json转换少8个小时的问题
    time-zone: GMT+8
    # 解决json返回过程中long的精度丢失问题
    generator:
      write-numbers-as-strings: true
      write-bigdecimal-as-plain: true
# mybatis-plus配置
#mybatis-plus:
#  mapper-locations: classpath*:/mappers/*.xml
#  configuration:
#    call-setters-on-nulls: true
#  type-aliases-package: com.thh.entity

application-dev.yml配置

spring:
  shardingsphere:
    #配置数据源
    datasource:
      #每个数据源的别名 主库从库
      names: ds0,ds1
      #主库
      ds0:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.50.99:3340/master_slave_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT&useSSL=false
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
      #从库
      ds1:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.50.99:3341/master_slave_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT&useSSL=false
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
    #配置默认数据源
    sharding:
      #默认数据源 主要用于写  这就是配置读写分离 如果不配置 会把三个节点都当做slave 写数据的时候会报错
      default-data-source-name: ds0
    #配置从节点  不配置的话  所有读操作也会在主节点
    masterslave:
      name: ms
      #主库
      master-data-source-name: ds0
      #从库
      slave-data-source-names: ds1
      #从节点负载均衡使用轮询机制
      load-balance-algorithm-type: round_robin
    #参数配置 显示sql
    props:
      sql:
        show:  true

UserController

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserMapper userMapper;

    @RequestMapping("addUser")
    public String insertUser(){
        User user = new User();
        user.setNickname("wxt"+ new Random().nextInt());
        user.setPassword(123456);
        user.setAge(19);
        user.setSex(0);
        userMapper.addUser(user);
        return "success";
    }

    @GetMapping("getUser")
    public List<User> getUser(){
        return userMapper.getUserList();
    }
}

User

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_user")
public class User {
    // 主键
    @TableId
    private Integer id;
    // 用户名
    private String nickname;
    private Integer password;
    // 年龄
    private Integer age;
    /**
     * 性别 0代表女 1代表男
     */
    private Integer sex;
}

UserMapper

public interface UserMapper {

    @Insert("insert t_user(nickname,password,age,sex) value(#{nickname},#{password},#{age},#{sex})")
    void addUser(User user);

    @Select("select * from t_user")
    List<User> getUserList();
}

启动类:

@SpringBootApplication
@MapperScan("com.xii.shardingjdbc.mapper")
public class ShardingjdbcApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShardingjdbcApplication.class, args);
    }
}

测试

当执行添加数据的时候,一直走的是ds0节点:
在这里插入图片描述

查询的时候:
在这里插入图片描述
一直为从节点ds1:
在这里插入图片描述

4.分库分表

必要知识:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

分库分表实战:

注意:分库分表只可以对主库进行分库分表操作,从库只有读,我仍然是用的上面主从分离的时候使用的库的名称,但都是主库,不要搞混。
在这里插入图片描述
两个库建数据库表:t_user_0,t_user_1

项目还是之前的项目,在配置文件中

标准分片策略 1

spring:
  shardingsphere:
    #配置数据源
    datasource:
      #每个数据源的别名 主库
      names: ds0,ds1
      #主库
      ds0:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.50.99:3340/master_slave_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT&useSSL=false
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
      #主库
      ds1:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.50.99:3341/master_slave_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT&useSSL=false
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
    #配置默认数据源
    sharding:
      #默认数据源 
      default-data-source-name: ds0
      #配置分表规则
      tables:
        #逻辑表名
        kst_user:
          #数据节点  数据源$->{0..N}.逻辑表名$->{0..N}
          actual-data-nodes: ds$->{0..1}.t_user_$->{0..1}
          #拆分库策略  什么样子数据放入哪个数据库
          database-strategy:
            inline:
              #分片算法
              algorithm-expression: ds$->{age % 2}
              #分片字段
              sharding-column: age
          #拆分表策略
          table-strategy:
            inline:
               #分片算法
               algorithm-expression: t_user_$->{age % 2}
               #分片字段
               sharding-column: age
    #参数配置 显示sql
    props:
      sql:
        show:  true

连接的两个数据库都要是主库
解释:

#数据节点  数据源$->{0..N}.逻辑表名$->{0..N}
          actual-data-nodes: ds$->{0..1}.t_user_$->{0..1}
          #拆分库策略  什么样子数据放入哪个数据库
          database-strategy:
            inline:
              #分片算法
              algorithm-expression: ds$->{age % 2}
              #分片字段
              sharding-column: age

actual-data-nodes: ds\$->{0..1}.t_user_$->{0..1}
对数据库分库 数据库有ds0和ds1后面的.数据表同样也是有t_user_0,t_user_1

algorithm-expression: ds$->{age % 2}
age对2取余,结果只会为0或者1,正对应两个数据库

测试结果
在这里插入图片描述
age为奇数,进入的是ds1库中的t_user_1表
在这里插入图片描述

age为0的时候进入的是ds0库中的t_user_0表
在这里插入图片描述

标准分片策略 2

在这里插入图片描述

配置文件:

spring:
  shardingsphere:
    #配置数据源
    datasource:
      #每个数据源的别名 主库
      names: ds0,ds1
      #主库
      ds0:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.50.99:3340/master_slave_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT&useSSL=false
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
      #主库
      ds1:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.50.99:3341/master_slave_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT&useSSL=false
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        username: root
    #配置默认数据源
    sharding:
#      #默认数据源 主要用于写
      default-data-source-name: ds0
#    #配置从节点  不配置的话  所有读操作也会在主节点
#    masterslave:
#      name: ms
#      #主库
#      master-data-source-name: ds0
#      #从库
#      slave-data-source-names: ds1
#      #从节点负载均衡使用轮询机制
#      load-balance-algorithm-type: round_robin

#    binding-tables: t_user
#      default-database-strategy:
#        inline:
#          algorithm-expression: ds0
#          sharding-column: user_id
      #配置分表规则
      tables:
        #逻辑表名
        kst_user:
          #数据节点  数据源$->{0..N}.逻辑表名$->{0..N}
          actual-data-nodes: ds$->{0..1}.t_user_$->{0..1}
          #拆分库策略  什么样子数据放入哪个数据库
          database-strategy:
            standard:
              shardingColumn: birthday
              preciseAlgorithmClassName: com.xii.shardingjdbc.config.BirthdayAlgorithm
          #拆分表策略
          table-strategy:
            inline:
               #分片算法
               algorithm-expression: t_user_$->{age % 2}
               #分片字段
               sharding-column: age
    #参数配置 显示sql
    props:
      sql:
        show:  true

这里面主要是对生日进行划分,在配置类中配置:
在这里插入图片描述
对生日进行判断,写一个配置类

public class BirthdayAlgorithm implements PreciseShardingAlgorithm<Date> {

    List<Date> dateList = new ArrayList<>();
    {
        //设置日期
        Calendar instance = Calendar.getInstance();
        instance.set(2000,1,1,0,0,0);
        Calendar instance2 = Calendar.getInstance();
        instance2.set(2022,1,1,0,0,0);
        dateList.add(instance.getTime());
        dateList.add(instance2.getTime());

    }

    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
        //获取数据真实属性
        Date value = shardingValue.getValue();
        //获取数据源名称列表
        Iterator<String> iterator = availableTargetNames.iterator();
        String target = "";
        for (Date s : dateList) {
            target = iterator.next();
            //数据早于指定日期直接返回    1999 早于2000 返回 所以1999会进入ds0库
            if(value.before(s)){
                break;
            }
        }
        return target;
    }
}

测试
在这里插入图片描述
成功:
在这里插入图片描述

分布式主键配置

因为不同的表使用自增id的话,会造成id冲突,所以在这里使用雪花算法id,配置:
在这里插入图片描述

#配置主键策略  避免主键重复
          key-generator:
            column: id
            #雪花算法
            type: SNOWFLAKE

注意id类型 是long
在这里插入图片描述

定义返回主键:
在这里插入图片描述

测试

在这里插入图片描述
成功!

日期分表

定义配置文件:
在这里插入图片描述

controller
在这里插入图片描述
这样就可以按照传过来的日期分表,但是注意如果没有命中条件的话,会报错。

另外如果sql没有对应的字段的话,
在这里插入图片描述
他会将所有的表都插进去数据,这也是一个问题。

分页统计和实现

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
虽然分表了,但是我们看到查询分页的时候也是没有问题的,因为shardingjdbc已经帮我们做好了,形成一个笛卡尔乘积进行搜索,但是可能会稍微影响点性能

5 shardingjdbc的事务管理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

6 总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杵意

谢谢金主打赏呀!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值