之前研究了 MySQL 通过主从复制的方式,使用 Sharding-JDBC 实现读写分离。

  • MySQL如何配置读写分离?
  • 项目中如何实现读写分离?怎么配置?


读写分离可以提高系统的并发访问量,但是如果存在单表过大的情况,就不得不进行分库分表了。

分库分表的实现方案

一般分为两种:1、增加一个中间层,中间层实现 MySQL 客户端协议,可以做到应用程序无感知地与中间层交互。由于是基于协议层的代理,可以做到支持多语言,但需要多启动一个进程、SQL 的解析也耗费大量性能、由于协议绑定仅支持单个种类的数据库库。2、在代码层面增加一个路由程序,控制对数据库与表的读写。路由程序写在项目里,与编程语言绑定、连接数高、但相对轻量(比如 Java 仅需要引入 SharingShpere 组件中 Sharding-JDBC 的 jar 即可)、支持任意数据库。

代码怎么写?怎么配?

以 Sharding-JDBC 实现分库分表为例子
1、数据库环境准备两个数据库,之前演示用了主库:172.31.32.184从库:172.31.32.234现在执行 stop slave 指令,把从库自动同步主库停掉,改为
ds0:172.31.32.184ds1:172.31.32.234用作分库



2、在 ds0 和 ds1 库中建表,t_order0 和 t_order1 用做分表

create table t_order0(
order_id int primary key,
user_id int
goods_id int,
goods_name varchar(200)
);

create table t_order1(
order_id int primary key,
user_id int
goods_id int,
goods_name varchar(200)
);



3、新建 maven 项目,添加依赖

<!-- 当前最新版 sharding-jdbc -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-core</artifactId>
    <version>4.1.1</version>
</dependency>
<!-- 结合官方文档使用了 HikariCP 数据库连接池 -->
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>3.4.5</version>
</dependency>
<!-- MySQL 8.0.21 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.21</version>
</dependency>



4、数据源连接工具类,使用 HikariCP 数据库连接池

 1package constxiong;
2
3import com.zaxxer.hikari.HikariDataSource;
4
5/**
6 * 获取 DataSource 工具类,使用了 Hikari 数据库连接池
7 */

8import javax.sql.DataSource;
9
10public final class DataSourceUtil {
11
12    private static final int PORT = 3306;
13
14    /**
15     * 通过 Hikari 数据库连接池创建 DataSource
16     * @param ip
17     * @param username
18     * @param password
19     * @param dataSourceName
20     * @return
21     */

22    public static DataSource createDataSource(String ip, String username, String password, String dataSourceName) {
23        HikariDataSource result = new HikariDataSource();
24        result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
25        result.setJdbcUrl(String.format("jdbc:mysql://%s:%s/%s?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8", ip, PORT, dataSourceName));
26        result.setUsername(username);
27        result.setPassword(password);
28        return result;
29    }
30}



5、测试代码

测试逻辑:

  • 使用数据源工具类,新建 ds0 和 ds1 库的数据源

  • 配置 t_order 表的规则,ds$->{0..1}.t_order$->{0..1}

  • 配置分库分表的规则,分库根据 ds  拼接上 t_order 的 user_id 字段值 对 2 取模的值(ds${user_id % 2});分表根据 t_order  拼接上 order_id 字段值 对 2 取模的值(t_order${order_id % 2}

  • 测试 insert 不同的 user_id 和 order_id 是否会按规则插入不同的库和表

  • 查询 user_id = 2 的数据,看看是否正常查出


 1package constxiong;
2
3import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
4import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
5import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
6import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
7
8import javax.sql.DataSource;
9import java.sql.Connection;
10import java.sql.ResultSet;
11import java.sql.SQLException;
12import java.sql.Statement;
13import java.util.HashMap;
14import java.util.Map;
15import java.util.Properties;
16
17/**
18 * 测试 ShardingSphere 分表分库
19 */

20public class Test {
21
22    //DataSource 0
23    private static DataSource ds0 = DataSourceUtil.createDataSource("172.31.32.234""root""constxiong@123""constxiong");
24    // DataSource 1
25    private static DataSource ds1 = DataSourceUtil.createDataSource("172.31.32.184""root""constxiong@123""constxiong");
26
27    public static void main(String[] args) throws SQLException {
28        // 配置真实数据源
29        Map<String, DataSource> dataSourceMap = new HashMap<>();
30        dataSourceMap.put("ds0", ds0);
31        dataSourceMap.put("ds1", ds1);
32
33        // 配置Order表规则
34        TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration("t_order""ds$->{0..1}.t_order$->{0..1}");
35
36        // 配置分库 + 分表策略
37        orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id""ds${user_id % 2}"));
38        orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id""t_order${order_id % 2}"));
39
40        // 配置分片规则
41        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
42        shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
43
44        // 获取数据源对象
45        DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, new Properties());
46        Connection connection = dataSource.getConnection();
47        Statement statement = connection.createStatement();
48        statement.execute("insert into t_order value(1, 1, 1, '电视机')");
49        statement.execute("insert into t_order value(2, 1, 2, '可乐')");
50        statement.execute("insert into t_order value(3, 2, 8, '空调')");
51        statement.execute("insert into t_order value(4, 2, 9, '手机壳')");
52
53        statement.execute("select * from t_order where user_id = 2");
54        ResultSet resultSet = statement.getResultSet();
55        while (resultSet.next()) {
56            System.out.printf("user_id:%d, order_id:%d, goods_id:%d, goods_name:%s\n",
57                    resultSet.getInt("user_id"),
58                    resultSet.getInt("order_id"),
59                    resultSet.getInt("goods_id"),
60                    resultSet.getString("goods_name")
61            );
62        }
63    }
64}

6、结果数据按照分库分表的规则插入对应的数据库与表中

图片


user_id = 2 数据代码查询

user_id:2order_id:4goods_id:9goods_name:手机壳
user_id:2order_id:3goods_id:8goods_name:空调


补充

  • 文中通过 JDBC 方式实现数据库操作,先弄明白了原生,后面再来看 SpringBoot 的配置才能知道哪些类接收处理了参数,底层调用了哪些 API,框架整合的时候出了问题可以快速排查。

  • Sharding-JDBC 在实现分库分表时,涉及了很多概念,如逻辑表、真实表、数据节点、绑定表、广播表。文中代码里的 insert、select 语句里的 t_order 就是逻辑表,实际插入与查询是在 t_order0 和 t_order1 表。

  • ds$->{0..1}.t_order$->{0..1},$->{0..1} 表示范围区间,取 0、1,这些配置规则在官方文档中都有说明。

  • 官方文档也列出了 Sharding-JDBC 不支持的功能,如不支持存储过程,函数,游标的操作等。技术选型的时候,不能忽视它的能力范围。


更多相关文章

  1. 【MySQL】数据库版本升级:mysql 5.6 升级到 mysql 5.7
  2. Druid数据库连接池就是这么简单
  3. Springboot整合mybatis多数据源(注解完整版)
  4. 阿里的OceanBase数据库世界第一,底层原来是用了Paxos协议
  5. 数据库面试题(开发者必看)
  6. Flyway 助力数据库脚本自动化管理攻略
  7. 使用mysql数据库,遇到重复数据怎么处理?
  8. 服务端开发指南与最佳实战 | 数据存储技术 | MySQL(06) 数据库安全
  9. sql.js:JS专用的内存型数据库[github项目精选0x01]

随机推荐

  1. Android(安卓)-- Intent
  2. Android 实现全屏和无标题栏的显示
  3. Google Android(安卓)SDK开发范例-------
  4. Android(安卓)NDK 知识系列(三)
  5. 用android:clipChildren来实现红心变大特
  6. Android Library Project 使用问题总结
  7. android系统中自带的各种图标
  8. android 代码混淆之后 微信分享不起作用
  9. Force Localize an Application on Andro
  10. Android NDK 环境搭建(Native Developmen