JDBC-读写分离

2023-01-11 ShardingSphere分库分表

ShardingSphere (opens new window)由JDBC、Proxy和Sidecar(规划中)构成,其中Sidecar还在规划中暂不使用,JDBC定位为轻量级Java框架,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动; Proxy定位为透明化的数据库代理端,目前提供MySQL和PostgreSQL版本,向应用程序完全透明,可直接当做 MySQL/PostgreSQL 使用;

总结来说,JDBC相当于是一个java框架,通过jar包来提供服务,管理多个数据库的各项功能;而Proxy则是一个中间件,对代码无侵入性,直接管理各个数据库,应用程序直接连接Proxy就和使用MySQL一样简单。

本片文章讲解ShardingSphere-JDBC中的读写分离 (opens new window)功能,首先需要搭建SpringBoot工程项目,然后按照官方文档一步步进行读写分离配置,当然前提条件是MySQL数据库已经进行了主从数据库的配置。

# 1. 创建SpringBoot程序

<dependencies>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
        <version>5.1.1</version>
    </dependency>
</dependencies>

# 1.1 创建实体类

@TableName("t_user")
@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String uname;
}

# 1.2 创建Mapper

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

# 1.3 配置读写分离

application.properties:

# 应用名称
spring.application.name=sharging-jdbc-demo
# 开发环境设置
spring.profiles.active=dev
# 内存模式
spring.shardingsphere.mode.type=Memory

# 配置真实数据源
spring.shardingsphere.datasource.names=master,slave1,slave2

# 配置第 1 个数据源
spring.shardingsphere.datasource.master.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.master.jdbc-url=jdbc:mysql://192.168.100.201:3306/db_user
spring.shardingsphere.datasource.master.username=root
spring.shardingsphere.datasource.master.password=123456

# 配置第 2 个数据源
spring.shardingsphere.datasource.slave1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave1.jdbc-url=jdbc:mysql://192.168.100.201:3307/db_user
spring.shardingsphere.datasource.slave1.username=root
spring.shardingsphere.datasource.slave1.password=123456

# 配置第 3 个数据源
spring.shardingsphere.datasource.slave2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.slave2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.slave2.jdbc-url=jdbc:mysql://192.168.100.201:3308/db_user
spring.shardingsphere.datasource.slave2.username=root
spring.shardingsphere.datasource.slave2.password=123456

# 读写分离类型,如: Static,Dynamic
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.type=Static
# 写数据源名称
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.props.write-data-source-name=master
# 读数据源名称,多个从数据源用逗号分隔
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.props.read-data-source-names=slave1,slave2

# 负载均衡算法名称
spring.shardingsphere.rules.readwrite-splitting.data-sources.myds.load-balancer-name=alg_round

# 负载均衡算法配置
# 负载均衡算法类型
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_round.type=ROUND_ROBIN
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_random.type=RANDOM
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_weight.type=WEIGHT
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_weight.props.slave1=1
spring.shardingsphere.rules.readwrite-splitting.load-balancers.alg_weight.props.slave2=2

# 打印SQl
spring.shardingsphere.props.sql-show=true

# 2. 配置分析

  1. 模式配置:模式配置 (opens new window),测试时使用内存模式,运行模式说明可点击跳转 (opens new window)
  2. 数据源配置:第二步就是数据源配置 (opens new window),给三个数据源分别起了3个名字分别是master、slave1、slave2,在配置数据源时指定这些名字。
  3. 读写分离:读写分离 (opens new window)配置,master是写数据源,slave1,slave2是读数据源,MySQL配置了主从数据库,主数据库发生变动,从数据库会跟着改变。
  4. 负载均衡算法:负载均衡算法官方文档 (opens new window)有提到,包含ROUND_ROBIN(轮询算法)、RANDOM(随机访问算法)、WEIGHT(权重访问算法)

# 3.读写分离功能测试

读写分离测试,写入数据发现三台数据库均能写入数据,读数据发现读出来的是两台从库的数据,uname字段的第二条记录在三台机器都是不一样的,多测试即便发现读出来的是两台从库的数据。至此,读写分离功能测试正常。

@SpringBootTest
class DistributedShardingApplicationTests {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert() {
        User user = new User();
        user.setUname("张三丰");
        userMapper.insert(user);
    }

	@Test
	public void testSelect() {
		List<User> userList1 = userMapper.selectList(null);
        List<User> userList2 = userMapper.selectList(null);
		System.out.println(userList1);
        System.out.println(userList2);
	}
}

也可以在web请求中测试负载均衡

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

    @Autowired
    private UserMapper userMapper;

    @GetMapping("selectAll")
    public void selectAll(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

# 事务测试

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

  • 不添加@Transactional:insert对主库操作,select对从库操作
  • 添加@Transactional:则insert和select均对主库操作
  • **注意:**在JUnit环境下的@Transactional注解,默认情况下就会对事务进行回滚(即使在没加注解@Rollback,也会对事务回滚)
@Test
@Transactional  //开启事务
public void testTrans() {
    User user = new User();
    user.setUname("铁锤");
    userMapper.insert(user);
    List<User> users = userMapper.selectList(null);
}
上次更新: 1 年前