zl程序教程

您现在的位置是:首页 >  其他

当前栏目

ShardingSphere实现读写分离

2023-03-07 09:41:04 时间

文章目录

完整代码已上传 Gitee Spring整合常用组件

前提条件

MySQL主从同步已搭建完成。参考链接

相关DDL:

CREATE DATABASE db_user;
USE db_user;
CREATE TABLE t_user (
 id BIGINT AUTO_INCREMENT,
 uname VARCHAR(30),
 PRIMARY KEY (id)
);
INSERT INTO t_user(uname) VALUES('zhang3');
INSERT INTO t_user(uname) VALUES(@@hostname);

1、创建SpringBoot程序

1.1、创建项目

项目名:sharding-jdbc-demo

SpringBoot版本:2.5.9

1.2、添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
        <version>5.1.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

1.3、创建实体类

package org.example.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * @description: PO实体类
 * @author: yh
 * @date: 2022/9/18
 */
@TableName("t_user")
@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String uname;
}

1.4、创建Mapper

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

1.5、Controller

@RestController
@RequestMapping(value = "/user")
public class UserController {
    @Resource
    private UserMapper userMapper;

    /**
     * 插入数据,测试是否写入master
     * 如果开启事务,读会走master数据源
     * @author: yh
     * @date: 2022/9/18
     */
//    @Transactional
    @GetMapping("/insert")
    public void userInsert(){
        User u = new User();
        u.setUname("西门庆"+System.currentTimeMillis());
        userMapper.insert(u);
//        List<User> users = userMapper.selectList(null);
//        System.out.println(users.size());
    }

    /**
     * 查询
     * @author: yh
     * @date: 2022/9/18
     */
    @GetMapping("/selectAll")
    public void selectAll(){
        userMapper.selectList(null);
    }
}

1.6、配置读写分离

application.yml:

spring:
  application:
    name: sharging-jdbc-demo
  profiles:
    active: dev

application-dev.yml:

# 读写分离配置
spring:
  shardingsphere:
    datasource:
      # 配置真实数据源
      names: master,slave1,slave2
      # 配置第 1 个数据源
      master:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://192.168.1.1:3306/db_user
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      # 配置第 2 个数据源
      slave1:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://192.168.1.1:3307/db_user
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
      # 配置第 3 个数据源
      slave2:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://192.168.1.1:3308/db_user
        password: 123456
        type: com.zaxxer.hikari.HikariDataSource
        username: root
    mode:
      # 内存模式
      type: Memory
    # 打印sql
    props:
      sql-show: true
    rules:
      readwrite-splitting:
        data-sources:
          myds:
            # 读数据源负载均衡算法名称
            load-balancer-name: alg_round
            props:
              # 读数据源名称,多个从数据源用逗号分隔
              read-data-source-names: slave1,slave2
              # 写数据源名称
              write-data-source-name: master
            # 读写分离类型,如: Static,Dynamic
            type: Static
        load-balancers:
          # 定义负载均衡算法:随机,轮询,权重
          alg_random:
            type: RANDOM
          alg_round:
            type: ROUND_ROBIN
          alg_weight:
            props:
              slave1: 1
              slave2: 2
            type: WEIGHT

2、测试

2.1、读写分离测试

启动App Server,请求http://127.0.0.1:8080/user/insert

写入主数据源后,查询主数据库中数据是否写入,从数据库数据是否正常同步

2.2、事务测试

为了保证主从库间的事务一致性,避免跨服务的分布式事务,ShardingSphere-JDBC的主从模型中,事务中的数据读写均用主库

  • 不添加@Transactionalinsert对主库操作,select对从库操作
  • 添加@Transactional:则insertselect均对主库操作
  • 注意: 如果在JUnit环境下的@Transactional注解,默认情况下就会对事务进行回滚(即使在没加注解@Rollback,也会对事务回滚)
@Transactional
@GetMapping("/insert")
public void userInsert(){
    User u = new User();
    u.setUname("西门庆"+System.currentTimeMillis());
    userMapper.insert(u);
    List<User> users = userMapper.selectList(null);
    System.out.println(users.size());
}

2.3、负载均衡测试

load-balancer-name: alg_round  # 轮询

查询6次结果:slave1,slave2,slave1,slave2,slave1,slave2。结果轮询

load-balancer-name: alg_weight  # 权重

访问9次:slave1数据库3次,slave2数据库6次。权重 1:2

load-balancer-name: alg_random # 随机

访问6次:slave2,slave2,slave1,slave2,slave2,slave1,slave1。结果随机

到此,本章内容就介绍完啦