前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Sharding-JDBC 实现分库分表

Sharding-JDBC 实现分库分表

作者头像
凡人飞
发布于 2020-09-21 03:06:57
发布于 2020-09-21 03:06:57
1.1K00
代码可运行
举报
文章被收录于专栏:指缝阳光指缝阳光
运行总次数:0
代码可运行

一、概述

  1. 分库分表介绍:当数据量变大以后,单库单表已经不能满足需求。此时就需要进行拆分,拆分纬度分为垂直拆分和水平拆分。
    • 水平拆分:比如 服务器1 上有 user_0, order_0; 服务器2 上有 user_1, order_1。此时 user_0 和 user_1 一起组成了用户表。
    • 垂直拆分:用户表 放在服务器1上,订单表 放在服务器2上。
  2. 此处模拟使用两个数据库,每个数据库建两张表。库的拆分使用 city 字段(按城市存不同的库),表的拆分使用 id 取模。

二、数据准备

  1. 引入 pom :
代码语言:javascript
代码运行次数:0
运行
复制
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1.tmp</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.12</version>
</dependency>

<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>sharding-jdbc-config-spring</artifactId>
    <version>1.5.4.1</version>
</dependency>
  1. 新建两个数据库(可以同一个服务器上,也可以两个服务器上)。
代码语言:javascript
代码运行次数:0
运行
复制
CREATE DATABASE `xjf_0` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
CREATE DATABASE `xjf_1` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
  1. 在两个库中分别建如下两张表:
代码语言:javascript
代码运行次数:0
运行
复制
CREATE TABLE `user_0` (
  `id` BIGINT(64) NOT NULL,
  `city` VARCHAR(20) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB  DEFAULT CHARSET=utf8;

CREATE TABLE `user_1` (
  `id` BIGINT(64) NOT NULL,
  `city` VARCHAR(20) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB  DEFAULT CHARSET=utf8;

三、分库分表配置

  1. 在 resource 目录下新建 sharding.xml。配置如下,记得数据库连接修改为你自己的:
代码语言:javascript
代码运行次数:0
运行
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:rdb="http://www.dangdang.com/schema/ddframe/rdb"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.dangdang.com/schema/ddframe/rdb
                        http://www.dangdang.com/schema/ddframe/rdb/rdb.xsd
                        ">
    <!--======================================================分库分表===开始=================================================-->
    <!-- inline 表达式报错解决:在 Spring 的配置文件中,由于 inline 表达式使用了 Groovy 语法, Groovy 语法的变量符与 Spring 默认占位符
                               同为 ${} ,因此需要在配置文件中增加下面这行来解决解析报错问题-->
    <context:property-placeholder ignore-unresolvable="true" />

    <!-- 第一个数据库 -->
    <bean id="ds_0" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" primary="true">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/xjf_0?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>

    <!-- 第二个数据库 -->
    <bean id="ds_1" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/xjf_1?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>

    <!-- 配置分库规则: 根据 city 来分库,同一个城市的数据存同一个数据库中 -->

    <rdb:strategy id="databaseShardingStrategy" sharding-columns="city"
                  algorithm-class="com.xjf.sharding.algorithm.MySingleKeyDbShardingAlgorithm" />

    <!-- 配置分表规则 -->
    <rdb:strategy id="tableShardingStrategy" sharding-columns="id"
                  algorithm-class="com.xjf.sharding.algorithm.MyUserSingleKeyTableShardingAlgorithm" />

    <!-- 配置分库分表数据源 -->
    <rdb:data-source id="dataSource">
        <rdb:sharding-rule data-sources="ds_0, ds_1">
            <rdb:table-rules>
                <rdb:table-rule logic-table="user" actual-tables="user_${0..1}"
                                database-strategy="databaseShardingStrategy" table-strategy="tableShardingStrategy">
                    <!-- 使用 Sharding-JDBC 的默认 ID 生成器,基于雪花算法。-->
                    <rdb:generate-key-column column-name="id" />
                </rdb:table-rule>
            </rdb:table-rules>
        </rdb:sharding-rule>
    </rdb:data-source>

    <!--======================================================分库分表===结束=================================================-->


    <!-- 给 MyBatis-Plus 配置数据源 -->
    <bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>
  1. 在启动类上添加对应注解,引入 sharding.xml。
代码语言:javascript
代码运行次数:0
运行
复制
@ImportResource(locations = "classpath:sharding.xml")
@MapperScan("com.xjf.sharding.mapper")
@SpringBootApplication
public class ShardingApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShardingApplication.class, args);
    }
} 

四、自定义分库和分表算法

  1. 分库算法,使用 city 来区分:
代码语言:javascript
代码运行次数:0
运行
复制
public class MySingleKeyDbShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<String> {
    private static Map<String, List<String>> shardingMap = new ConcurrentHashMap<>();

    static {
        shardingMap.put("ds_0", Arrays.asList("上海"));
        shardingMap.put("ds_1", Arrays.asList("杭州"));
    }

    @Override
    public String doEqualSharding(Collection<String> collection, ShardingValue<String> shardingValue) {
        for (String each : collection) {
            System.err.println("数据库:" + each);
            System.err.println("添加数据的城市:" + shardingValue.getValue());
            if (shardingMap.get(each).contains(shardingValue.getValue())){
                return each;
            }
        }

        // 默认保存在数据库 "ds_0" 中
        return "ds_0";
    }

    @Override
    public Collection<String> doInSharding(Collection<String> collection, ShardingValue<String> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(collection.size());

        for (String each : collection) {
            if (shardingMap.get(each).contains(shardingValue.getValue())){
                result.add(each);
            }else {
                result.add("ds_0");
            }
        }

        return result;
    }

    @Override
    public Collection<String> doBetweenSharding(Collection<String> collection, ShardingValue<String> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(collection.size());

        for (String each : collection) {
            if (shardingMap.get(each).contains(shardingValue.getValue())){
                result.add(each);
            }else {
                result.add("ds_0");
            }
        }

        return result;
    }
} 
  1. 分表算法,id 取模:
代码语言:javascript
代码运行次数:0
运行
复制
public class MyUserSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {

    /**
     * 在 where 使用 = 作为条件分片键
     */
    @Override
    public String doEqualSharding(Collection<String> collection, ShardingValue<Long> shardingValue) {
        System.err.println("运行方法: doEqualSharding");

        for (String each : collection) {
            System.err.println("表:" + each);
            System.err.println("shardingValue.getValue: " + shardingValue.getValue());

            // 配合测试分库分表,取模是只有 2 张表。在测试不分库只分表时是 4 张表。分别对应使用
//            if (each.endsWith(shardingValue.getValue() % 4 +"")){
            if (each.endsWith(shardingValue.getValue() % 2 +"")){
                return each;
            }
        }

        throw new IllegalArgumentException();
    }

    /**
     * 在 where 使用 in 作为条件分片键
     */
    @Override
    public Collection<String> doInSharding(Collection<String> collection, ShardingValue<Long> shardingValue) {
        System.err.println("运行方法: doInSharding");

        Collection<String> result = new LinkedHashSet<>(collection.size());

        for (Long value : shardingValue.getValues()) {
            for (String tableName : collection) {
                if (tableName.endsWith(value % 4 + "")){
                    result.add(tableName);
                }
            }
        }

        return result;
    }

    /**
     * 在 where 使用 between 作为条件分片键
     */
    @Override
    public Collection<String> doBetweenSharding(Collection<String> collection, ShardingValue<Long> shardingValue) {
        System.err.println("运行方法: doBetweenSharding");

        Collection<String> result = new LinkedHashSet<>(collection.size());

        Range<Long> range = shardingValue.getValueRange();
        for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
            for (String each : collection) {
                if (each.endsWith( i % 4 + "")){
                    result.add(each);
                }
            }
        }

        return result;
    }
}

五、测试

  1. 在 controller 中添加插入数据的方法。id 的生成使用 Sharding-JDBC 默认的分布式主键(基于雪花算法),当程序在多个服务器上时,需要分别为机器在系统环境变量中设置 sharing-jdbc.default.key.generator.worker.id
代码语言:javascript
代码运行次数:0
运行
复制
@GetMapping("/add3")
public String add3(){

    for (int i = 0; i < 100; i++) {
        User user = new User();
        // 不设置 ID,在 sharding.xml 配置了 Sharding-JDBC 的默认分布式主键生成,是采用雪花算法实现的。
        // 在类 com.dangdang.ddframe.rdb.sharding.keygen.DefaultKeyGenerator 中
//            user.setId(Long.valueOf(i));
        // 随机设置城市
        int random = new Random().nextInt();
        if (random % 2 == 0){
            user.setCity("上海");
        }else {
            user.setCity("杭州");
        }
        user.setName("嘉文四世");

        userMapper.insert(user);
    }

    return "success";
}
  1. 调用方法,可以在分别的两个数据库,四张表中查看数据。其中数据总数加起来刚好 100 条。

看《Spring Cloud微服务入门、实战与进阶》

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/02/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
利用sharding-jdbc分库分表
sharding-jdbc是当当开源的一款分库分表的数据访问层框架,能对mysql很方便的分库、分表,基本不用修改原有代码,只要配置一下即可,完整的配置参考以下内容: 1 <?xml versio
菩提树下的杨过
2018/01/18
1.2K0
sharding-jdbc之——分库分表实例
转载请注明出处:http://blog.csdn.net/l1028386804/article/details/79368021
庞小明
2018/09/19
1.4K0
sharding-jdbc之——分库分表实例
1 SpringBoot 使用sharding jdbc进行分库分表
分库分表在数据量大的系统中比较常用,解决方案有Cobar,TDDL等,这次主要是拿当当网开源的Sharding-JDBC来做个小例子。 它的github地址为:https://github.com/dangdangdotcom/sharding-jdbc 简介: Sharding-JDBC直接封装JDBC API,可以理解为增强版的JDBC驱动,旧代码迁移成本几乎为零: 可适用于任何基于java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。 可基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid等。 理论上可支持任意实现JDBC规范的数据库。虽然目前仅支持MySQL,但已有支持Oracle,SQLServer,DB2等数据库的计划。 Sharding-JDBC定位为轻量级java框架,使用客户端直连数据库,以jar包形式提供服务,未使用中间层,无需额外部署,无其他依赖,DBA也无需改变原有的运维方式。SQL解析使用Druid解析器,是目前性能最高的SQL解析器。 具体的介绍可以上它的文档那里看看,简单归纳起来就是,它是一个增强版的JDBC,对使用者透明,逻辑代码什么的都不用动,它来完成分库分表的操作;然后它还支持分布式事务(不完善)。看起来很不错的样子。 下面用个小例子来看一下分库分表的使用。使用的是SpringBoot,JPA(hibernate),druid连接池。
天涯泪小武
2019/01/17
1.6K0
Spring Boot中整合Sharding-JDBC单库分表示例
本文是Sharding-JDBC采用Spring Boot Starter方式配置第二篇,第一篇是读写分离讲解,请参考:《Spring Boot中整合Sharding-JDBC读写分离示例》
猿天地
2018/09/30
2.3K0
【死磕Sharding-jdbc】---基于ssm
本篇文章讲解如何在ssm(spring、springmvc、mybatis)结构的程序上集成sharding-jdbc(版本为1.5.4.1)进行分库分表; 假设分库分表行为如下:
用户1655470
2018/07/24
8780
SpringBoot使用Sharding-JDBC分库分表
有关Sharding-JDBC介绍这里就不在多说,之前Sharding-JDBC是当当网自研的关系型数据库的水平扩展框架,现在已经捐献给Apache,具体可以查看Github,地址是
lyb-geek
2019/03/07
1.3K0
SpringBoot使用Sharding-JDBC分库分表
Sharding-JDBC + MyBatis-Plus + Druid 实现读写分离(yml方式 和 xml方式)
一、概述 当业务数据越来越大时,就需要进行分库分表,而 Sharding-JDBC 框架就是能完整的实现分库分表、读写分离和分布式主键等功能。 此处实现读写分离功能。因为是测试,就在同一个 MySQL 中创建两个数据库来模拟。 Sharding-JDBC 的配置方式四种:Java,YAML,Spring命名空间和Spring Boot Starter。此处只讲 YAML 和 XML 方式。 二、数据准备 新建两个数据库:ds_0 和 ds_1CREATE DATABASE `ds_0` CHARACTER
凡人飞
2020/09/20
1.4K0
【死磕Sharding-jdbc】---数据源
以 com.dangdang.ddframe.rdb.sharding.example.jdbc.Main剖析分库分表配置与实现,其部分源码如下:
用户1655470
2018/07/24
8730
sharding-jdbc 分库分表的 4种分片策略,还蛮简单的
上文《快速入门分库分表中间件 Sharding-JDBC (必修课)》中介绍了 sharding-jdbc 的基础概念,还搭建了一个简单的数据分片案例,但实际开发场景中要远比这复杂的多,我们会按 SQL 中会出现的不同操作符 >、<、between and、in等,来选择对应数据分片策略。
程序员小富
2020/11/03
8.9K0
数据库分库分表中间件 Sharding-JDBC 源码分析 —— SQL 路由(二)之分库分表路由
本文主要基于 Sharding-JDBC 1.5.0 正式版 1. 概述 2. SQLRouteResult 3. 路由策略 x 算法 4. SQL 路由 5. DatabaseHintSQLRouter 6. ParsingSQLRouter 6.1 SimpleRoutingEngine 6.2 ComplexRoutingEngine 6.3 CartesianRoutingEngine 6.3 ParsingSQLRouter 主#route() ---- ---- 1. 概述 本文分享分表分库路
芋道源码
2018/03/02
2.9K1
数据库分库分表中间件 Sharding-JDBC 源码分析 —— SQL 路由(二)之分库分表路由
【死磕Sharding-jdbc】---基于 SSM 集成sharding-jdbc2.0.3
本篇文章讲解如何在ssm(spring、springmvc、mybatis)结构的程序上集成sharding-jdbc(版本为2.0.3)进行分库分表; 假设分库分表行为如下:
用户1655470
2018/08/03
8010
Sharding-JDBC:单库分表的实现
通过上面的优化,已经能满足大部分的需求了。只有一种情况需要我们再次进行优化,那就是单表的数量急剧上升,超过了1千万以上,这个时候就要对表进行水平拆分了。
猿天地
2019/07/30
2.8K0
Sharding-JDBC:单库分表的实现
利用Sharding-Jdbc实现分表
你们团队使用SpringMVC+Spring+JPA框架,快速开发了一个NB的系统,上线后客户订单跟雪花一样纷沓而来。
程序猿讲故事
2019/09/27
9790
利用Sharding-Jdbc实现分表
ShardingSphere 数据分片
其实很多人对分库分表多少都有点恐惧,其实我也是,总觉得这玩意是运维干的、数据量上来了或者sql过于复杂、一些数据分片的中间件支持的也不是很友好、配置繁琐等多种问题。
胖虎
2019/06/26
2K0
ShardingSphere 数据分片
Sharding-JDBC教程:Spring Boot整合Sharding-JDBC实现数据分表+读写分离
在上一篇文章介绍了如何使用Sharing-JDBC实现数据库的读写分离。读写分离的好处就是在并发量比较大的情况下,将查询数据库的压力 分担到多个从库中,能够满足高并发的要求。比如上一篇实现的那样,架构图如下:
方志朋
2021/04/26
4.5K0
Sharding-JDBC教程:Spring Boot整合Sharding-JDBC实现数据分表+读写分离
数据量大了一定要分表,分库分表Sharding-JDBC入门与项目实战
最近项目中不少表的数据量越来越大,并且导致了一些数据库的性能问题。因此想借助一些分库分表的中间件,实现自动化分库分表实现。调研下来,发现Sharding-JDBC目前成熟度最高并且应用最广的Java分库分表的客户端组件。
程序员白楠楠
2020/12/10
1.9K0
Sharding-JDBC 使用入门和基本配置
Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
宜信技术学院
2019/06/28
3.2K0
【死磕Sharding-jdbc】---路由&执行
继续以sharding-jdbc-example-jdbc模块中的com.dangdang.ddframe.rdb.sharding.example.jdbc.Main为基础,剖析分库分表简单查询SQ
用户1655470
2018/07/24
9560
Spring整合Sharding-JDBC分库分表详情
最初线上系统的业务量不是很大,业务数据量并不大,比如说单库的数据量在百万级别以下(事实上千万级别以下都还能支撑),那么MySQL的单库即可完成任何增/删/改/查的业务操作。随着业务的发展,单个DB中保存的数据量(用户、订单、计费明细和权限规则等数据)呈现指数级增长,那么各种业务处理操作都会面临单DB的IO读写瓶颈带来的性能问题。
品茗IT
2019/09/12
2.5K0
【死磕Sharding-jdbc】---强制路由
位于 sharding-jdbc-core模块下的包 com.dangdang.ddframe.rdb.sharding.hint中,核心类HintManagerHolder的部分源码如下:
用户1655470
2018/07/24
3.3K0
推荐阅读
相关推荐
利用sharding-jdbc分库分表
更多 >
目录
  • 一、概述
  • 二、数据准备
  • 三、分库分表配置
  • 四、自定义分库和分表算法
  • 五、测试
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档