SpringBoot + ShardingSphere 秒级分库分表!

Spring Boot 作为主流微服务框架,拥有成熟的社区生态。市场应用广泛,为了方便大家,整理了一个基于spring boot的常用中间件快速集成入门系列手册,涉及RPC、缓存、消息队列、分库分表、注册中心、分布式配置等常用开源组件,大概有几十篇文章,陆续会开放出来,感兴趣同学请提前关注&收藏

互联网高速发展,同时也带来的海量数据存储问题。传统关系型数据库的单库单表已经很难支撑,如何高效存储和访问这些数据,成为业内急需解决的问题。解决思路有两个方向:

  • NoSQL数据库,非关系型数据库,天然集成了类似分布式分片的功能,支持海量数据存储,但是不具备事务管理

  • 分库分表,对多个单库单表资源整合,并配备资源调度模块,从而形成一个具有海量数据储存的逻辑表。

今天我们主要介绍,如何基于Springboot快速集成分库分表框架,尽量做到开箱即用

当然除了ShardingSphere之外,还有其他分库分表框架,如:CobarMyCat

ShardingSphere介绍

ShardingSphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由 3 款相互独立,却又能够混合部署配合使用的产品组成。它们均提供标准化的数据分片、分布式事务和数据库治理功能

ShardingSphere 由三个子项目组成,形成一个完整的数据库解决方案。

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

适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

2、ShardingSphere-Proxy:定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。目前提供 MySQL/PostgreSQL 版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端操作数据,对 DBA 更加友好。

3、ShardingSphere-Sidecar(规划中):定位为 Kubernetes 的云原生数据库代理,以 Sidecar 的形式代理所有对数据库的访问。通过无中心、零侵入的方案提供与数据库交互的的啮合层,即 Database Mesh,又可称数据网格。

优势:

  • 解决方案完备性,它集客户端分片、代理服务器,以及分布式数据库的核心功能于一身。

  • 开发友好性,提供了友好的集成方式,业务开发人员只需要引入一个 JAR 包就能在业务代码中嵌入数据分片、读写分离、分布式事务、数据库治理等一系列功能。

  • 可插拔的系统扩展性:它的很多核心功能均通过插件的形式提供,供开发者排列组合来定制属于自己的独特系统。

项目示例

首先,新建一个工程spring-boot-bulking-sharding-sphere,在pom.xml 文件中添加分库分表的 starter 依赖包

<dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.0.0-RC1</version>
</dependency>

数据环境准备

分别创建两个数据库ds0ds1,在ds0数据库中创建 user_0user_2两张用户表

CREATE TABLE `user_0` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名',`age` int(11) NOT NULL  COMMENT '年龄',`address` varchar(128) COMMENT '地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='用户表';CREATE TABLE `user_2` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名',`age` int(11) NOT NULL  COMMENT '年龄',`address` varchar(128) COMMENT '地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

在ds1数据库中创建 user_1user_3两张用户表

CREATE TABLE `user_1` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名',`age` int(11) NOT NULL  COMMENT '年龄',`address` varchar(128) COMMENT '地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='用户表';CREATE TABLE `user_3` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_name` varchar(128) NOT NULL DEFAULT '' COMMENT '用户名',`age` int(11) NOT NULL  COMMENT '年龄',`address` varchar(128) COMMENT '地址',PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

我们采用Mybatis作为ORM框架,遵循Mybatis的开发流程,首先需要定义业务实体类UserMapper接口类文件,以及对应的sql语句的xml文件。

@Mapper
public interface UserMapper {Long addUser(User user);List<User> queryAllUser();User queryUserById(Long id);Page<User> querUserByPage();
}

Spring boot 框架最为闪亮的设计就是约定胜于配置,废弃了之前繁琐的xml形式定义Bean实例,将一系列框架的配置项迁移到 application.properties 中,借助 EnableAutoConfiguration自动完成装载,并实例化相应的Bean实例到 spring 容器中,IOC统一管理。

针对两个数据库初始化两个DataSource对象,这两个 DataSource 对象将组成一个 Map 并传递给ShardingDataSourceFactory 工厂类,application.properties 配置文件:

server.port=8090
application.name=spring-boot-bulking-sharding-sphere
mybatis.config-location=classpath:config/mybatis-config.xml
spring.shardingsphere.datasource.names=ds0,ds1# 数据源
spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost:3306/ds0?characterEncoding=utf-8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=111111
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/ds1?characterEncoding=utf-8
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=111111

搞定数据源后,接下来我们需要设置分库、分表策略。

# 不分表(application.properties没有为表单独配置),默认数据源策略
spring.shardingsphere.sharding.default-data-source-name=ds1# user表的分表配置
spring.shardingsphere.sharding.tables.user.actual-data-nodes=ds0.user_$->{[0,2]},ds1.user_$->{[1,3]}
# user库策略(也可以采用默认的)
spring.shardingsphere.sharding.tables.user.database-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user.database-strategy.inline.algorithm-expression=ds$->{id % 2}
# user表策略
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 4}
#spring.shardingsphere.sharding.tables.user.key-generator.column=id
#spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE

在 ShardingSphere 中存在一组 ShardingStrategyConfiguration,这里使用的是基于行表达式的 InlineShardingStrategyConfiguration。

18fe88c94b813d8f3d1ff5a5c949c243.png

InlineShardingStrategyConfiguration包含两个参数,一个是指定分片列名称的 shardingColumn,另一个是指定分片算法行表达式的 algorithmExpression。上面的示例,将基于 id 列对 2 的取模值来确定数据应该存储在哪一个数据库中

我们对user表做了分库分表,拆分成4个表,并分别归属到两个库中。分表键是id字段。

通过单元测试,插入 10条用户记录,验收下数据的插入情况~

@Test
public void addUser() {for (long i = 1; i < 11; i++) {User user = User.builder().id(i).userName("TomGE").age(29).address("杭州").build();userMapper.addUser(user);System.out.println("插入用户成功,uid=" + user.getId());}}

其中id=4,id=8 两条记录,插入到ds0库的user_0表中。

09993bddf26564405e28446209524c31.png

项目源码

https://github.com/aalansehaiyang/spring-boot-bulking  模块:spring-boot-bulking-sharding-sphere

热衷于收集高并发、系统架构、微服务、消息中间件、 RPC框架、高性能缓存、搜索、分布式数据框架、分布式协同服务、分布式配置中心、中台架构、领域驱动设计、系统监控、系统稳定性等技术知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA基础之自定义容器实现

容器 容器主要是指Collection所包含的实现类&#xff0c;常用的有List、Map以及Set三种结构。本文主要介绍了几种常见的集合实现类&#xff0c;对它们进行自定义实现。 ArrayList&#xff1a;有序的容器列表&#xff0c;顺序存储着元素&#xff0c;可以使用下标进行索引&…

git reset, git checkout, git revert 区别 (译)

博客原文地址: http://blog.mexiqq.com/index.php/archives/3/题记&#xff1a;团队中大多数成员使用 sourceTree 和 github 两款 git 工具&#xff0c;然而大家对于图形化工具提供的 reset,checkout,revert 功能点并不是很了解&#xff0c;甚至于混淆,然后凭借猜测去使用。功夫…

Redis笔记之基本数据结构 动态字符串SDS

简单动态字符串 传统上的C语言的字符串表示是以空字符结尾的字符数组&#xff08;C字符串&#xff09;&#xff0c;redis自己实现一个动态字符串&#xff08;SDS&#xff09;&#xff0c;两者之间的区别以及使用SDS的好处有&#xff1a; 结构不同。C字符串以空字符结尾的字符…

weakhashmap_Java WeakHashMap size()方法与示例

weakhashmapWeakHashMap类的size()方法 (WeakHashMap Class size() method) size() method is available in java.util package. size()方法在java.util包中可用。 size() method is used to get the number of key-value pairs that exist in this map. size()方法用于获取此映…

扯一把 Spring 的三种注入方式,到底哪种注入方式最佳?

1. 实例的注入方式首先来看看 Spring 中的实例该如何注入&#xff0c;总结起来&#xff0c;无非三种&#xff1a;属性注入set 方法注入构造方法注入我们分别来看下。1.1 属性注入属性注入是大家最为常见也是使用最多的一种注入方式了&#xff0c;代码如下&#xff1a;Service p…

在项目中引入领域驱动设计的经验

Chris Patuzzo近期在一次演讲中介绍了领域驱动设计&#xff08;DDD&#xff09;的原则&#xff0c;并结合一个基于Ruby on Rails的真实项目进行讲解。在这次项目之前&#xff0c;Chris所在的团队为重新设计公司的主营网站所做的两个概念验证都因为可伸缩性方面的问题而失败了。…

Redis笔记之基本数据结构 链表

链表 链表具有空间存储不连续&#xff0c;增删节点快的优点&#xff0c;因此redis在列表键、发布与订阅、慢查询、监视器等使用了链表作为底层实现。由于C语言中没有内置的链表实现&#xff0c;因此redis自己进行了实现。 双向链表。每个listtNode都有perv和next指针&#x…

treeset java_Java TreeSet iterator()方法与示例

treeset javaTreeSet类的iterator()方法 (TreeSet Class iterator() method) iterator() method is available in java.util package. iterator()方法在java.util包中可用。 iterator() method is used to iterate the elements of this TreeSet is ascending or increasing or…

SpringCloud组件:Ribbon负载均衡策略及执行原理!

大家好&#xff0c;我是磊哥。今天我们来看下微服务中非常重要的一个组件&#xff1a;Ribbon。它作为负载均衡器在分布式网络中扮演着非常重要的角色。本篇主要内容如下&#xff1a;在介绍 Ribbon 之前&#xff0c;不得不说下负载均衡这个比较偏僻的名词。为什么说它偏僻了&…

Redis笔记之基本数据结构 字典

字典 符号表、关联数组或者映射&#xff0c;有点类似于java中的map&#xff0c;用于保存键值对key-value。字典中的键key是独一无二的。底层实现为哈希表。下面进行简述&#xff1a; 哈希表。哈希表主要包含table数组、size、sizemask以及used。table用于保存哈希表节点&…

【零基础学习iOS开发】【02-C语言】02-第一个C语言程序

本文目录 前言一、编写第一个C语言程序-Hello World二、编译程序三、链接程序四、运行程序五、总结六、学习建议七、clang指令汇总回到顶部前言 前面已经唠叨了这么多理论知识&#xff0c;从这讲开始&#xff0c;就要通过接触代码来学习C语言的语法。学习任何一门语言&#xff…

安卓平板体验Java开发,还能白嫖一年阿里无影云,真香!(内含白嫖方法,人人可领)...

作者 | 磊哥来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;阿里无影云早有耳闻&#xff0c;前两天看朋友发体验照片&#xff0c;可能是程序员天生爱折腾的特性又发挥作用了&#xff0c…

Linux命令(三)

echo&#xff1a;输出信息echo ”abc”echo “字符串” |passwd --stdin USERNAME :利用管道修改用户密码输出重定向&#xff1a;>覆盖输出&#xff08;会覆盖原文件中的内容&#xff09;>>追加输出 &#xff08;原有内容会被保留&#xff09;Set –c &#xff1a…

strictmath_Java StrictMath scalb()方法与示例

strictmathStrictMath类scalb()方法 (StrictMath Class scalb() method) Syntax: 句法&#xff1a; public static double scalb(double do , int sf);public static float scalb(float fl , int sf);scalb(double do , int sf) method is used to return do* 2 raised to the…

你知道group by的工作原理和优化思路吗?

前言 日常开发中&#xff0c;我们经常会使用到group by。亲爱的小伙伴&#xff0c;你是否知道group by的工作原理呢&#xff1f;group by和having有什么区别呢&#xff1f;group by的优化思路是怎样的呢&#xff1f;使用group by有哪些需要注意的问题呢&#xff1f;本文将跟大家…

strictmath_Java StrictMath hypot()方法与示例

strictmathStrictMath类hypot()方法 (StrictMath Class hypot() method) hypot() method is available in java.lang package. hypot()方法在java.lang包中可用。 hypot() method is used to return the square root of sqrt(sq(d1)sq(d2)) without any intermediate operation…

关Jquery判断input type=checkbox元素是否被选中的判断

2019独角兽企业重金招聘Python工程师标准>>> 在用到复选框的时候&#xff0c;想在js中判断chekbox是否被选中 <input name"isPermit" id"isPermit" type"checkbox"> 百度了很多的判断方法 1、 if($("#isPermit").att…

Redis夺命十二问,你能扛到第几问?

Redis是面试中绕不过的槛&#xff0c;只要在简历中写了用过Redis&#xff0c;肯定逃不过。今天我们就来模拟一下面试官在Redis这个话题上是如何一步一步深入&#xff0c;全面考察候选人对于Redis的掌握情况。小张&#xff1a;面试官&#xff0c;你好。我是来参加面试的。面试官…

Java Scanner nextLine()方法与示例

扫描仪类nextLine()方法 (Scanner Class nextLine() method) nextLine() method is available in java.util package. nextLine()方法在java.util包中可用。 nextLine() method is used to get the skipped line. nextLine()方法用于获取跳过的行。 nextLine() method is a non…

bzoj 1192

http://www.lydsy.com/JudgeOnline/problem.php?id1192 好像学过一个东西&#xff1a; [0..2^(N1)-1]内的数都的都可以由2^0,2^1,...,2^N这N1个数中若干个相加得到。 #include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #incl…