1. ShardingJDBC
1.1 分库分表方式回顾
分库分表的目的就是将我们的单库的数据控制在合理范围内,从而提高数据库的性能.
- 垂直拆分( 按照结构分 )
- 垂直分表: 将一张宽表(字段很多的表), 按照字段的访问频次进行拆分,就是按照表单结构进行拆
- 垂直分库: 根据不同的业务,将表进行分类, 拆分到不同的数据库. 这些库可以部署在不同的服务器,分摊访问压力.
- 水平拆分( 按照数据行分 )
- 水平分库: 将一张表的数据 ( 按照数据行) 分到多个不同的数据库.每个库的表结构相同. 每个库都只有这张表的部分数据,当单表的数据量过大,如果继续使用水平分库, 那么数据库的实例就会不断增加,不利于系统的运维. 这时候就要采用水平分表.
- 水平分表: 将一张表的数据 ( 按照数据行) , 分配到同一个数据库的多张表中,每个表都只有一部分数据.
什么时候用分库分表
- 在系统设计阶段,就要完成垂直分库和垂直分表. 在数据量不断上升,数据库性能无法满足需求的时候, 首先要考虑的是缓存、 读写分离、索引技术等方案.如果数据量不断增加,并且持续增长再考虑水平分库 水平分表.
1.2 分库分表带来的问题
关系型数据库在单机单库的情况下,比较容易出现性能瓶颈问题,分库分表可以有效的解决这方面的问题,但是同时也会产生一些 比较棘手的问题.
1.2.1 事务一致性问题
当我们需要更新的内容同时分布在不同的库时, 不可避免的会产生跨库的事务问题. 原来在一个数据库操作, 本地事务就可以进行控制, 分库之后 一个请求可能要访问多个数据库,如何保证事务的一致性,目前还没有简单的解决方案.
1.2.2 跨节点关联的问题
在分库之后, 原来在一个库中的一些表,被分散到多个库,并且这些数据库可能还不在一台服务器,无法关联查询.解决这种关联查询,需要我们在代码层面进行控制,将关联查询拆开执行,然后再将获取到的结果进行拼装.
1.2.3 分页排序查询的问题
分库并行查询时,如果用到了分页 每个库返回的结果集本身是无序的, 只有将多个库中的数据先查出来,然后再根据排序字段在内存中进行排序,如果查询结果过大也是十分消耗资源的.
1.2.4 主键避重问题
在分库分表的环境中,表中的数据存储在不同的数据库, 主键自增无法保证ID不重复, 需要单独设计全局主
键.
1.2.5 公共表的问题
不同的数据库,都需要从公共表中获取数据. 可以在每一个库都创建这个公共表, 所有对公共表的更新操作,都同时发送到所有分库执行. ShardingJDBC可以帮助我们解决这个问题.
1.3 ShardingJDBC 简介
1.3.1 什么是ShardingJDBC
ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、 Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。
我们只关注 Sharding-JDBC 即可.
官方地址:https://shardingsphere.apache.org/document/current/cn/overview/
Sharding-JDBC 定位为轻量级Java框架,在Java的JDBC层提供的额外服务。
它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架的使用。
- 适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
- 基于任何第三方的数据库连接池,如:DBCP, C3P0, Druid等。
- 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。
上图展示了Sharding-Jdbc的工作方式
-
使用Sharding-Jdbc前需要人工对数据库进行分库分表
-
在应用程序中加入Sharding-Jdbc的Jar包,应用程序通过Sharding-Jdbc操作分库分表后的数据库和数据表
-
由于Sharding-Jdbc是对Jdbc驱动的增强,使用Sharding-Jdbc就像使用Jdbc驱动一样,在应用程序中是无需指定具体要操作的分库和分表的。
1.3.2 Sharding-JDBC主要功能
- 数据分片
- 读写分离
通过Sharding-JDBC,应用可以透明的使用jdbc访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。
1.3.3 Sharding-JDBC与MyCat的区别
-
mycat是一个中间件的第三方应用,sharding-jdbc是一个jar包
-
使用mycat时不需要修改代码,而使用sharding-jdbc时需要修改代码
-
Mycat 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库,而Sharding-JDBC 是基于 JDBC 的扩展,是以 jar 包的形式提供轻量级服务的。
- Mycat(proxy中间件层)
- Sharding-jdbc(应用层):
1.4 Sharding-JDBC入门使用
1.4.1 搭建基础环境
需求说明:
- 创建数据库lg_order, 模拟将订单表进行水平拆分, 创建两张表pay_order_1 与 pay_order_2,这两 张表是订单表拆分后的表,
- 我们通过Sharding-Jdbc向订单表插入数据,按照一定的分片规则,主键为偶数的落入pay_order_1表 ,为奇数的落入pay_order_2表, 再通过Sharding-Jdbc 进行查询.
CREATE DATABASE lg_order CHARACTER SET 'utf8';
DROP TABLE IF EXISTS pay_order_1;
CREATE TABLE pay_order_1 (
order_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT ,
user_id INT(11) ,
product_name VARCHAR(128),
COUNT INT(11)
);
DROP TABLE IF EXISTS pay_order_2;
CREATE TABLE pay_order_2 (
order_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT ,
user_id INT(11) ,
product_name VARCHAR(128),
COUNT INT(11)
);
创建SpringBoot项目引入maven依赖
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
1.4.2 分片规则配置(水平分表)
要使用sharding-jdbc 对数据库中水平拆分的表进行操作,需要通过sharding-jdbc对分库分表的规则进行配置
配置内容包括:数据源、主键生成策略、分片策略等。
application.properties
# 基础配置
spring.application.name = sharding-jdbc-simple
server.servlet.context-path = /sharding-jdbc
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true
spring.main.allow-bean-definition-overriding = true
mybatis.configuration.map-underscore-to-camel-case = true
# 定义数据源
spring.shardingsphere.datasource.names = db1
spring.shardingsphere.datasource.db1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.db1.url = jdbc:mysql://localhost:3306/lg_order?characterEncoding=UTF-8&useSSL=false
spring.shardingsphere.datasource.db1.username = root
spring.shardingsphere.datasource.db1.password = 123456
# 配置数据节点,指定节点的信息
# 表达式 db1.pay_order_$->{
1..2}
# $ 会被大括号中的 {
1..2} 所替换,即db1.pay_order_1 和 db1.pay_order_2
spring.shardingsphere.sharding.tables.pay_order.actual-data-nodes = db1.pay_order_$->{
1..2}
# 配置主键生成策略
# 使用shardingJDBC提供的主键生成策略,全局主键
# 为避免主键重复, 生成主键采用 SNOWFLAKE 分布式ID生成算法
#指定pay_order表 (逻辑表)的主键生成策略为 SNOWFLAKE
spring.shardingsphere.sharding.tables.pay_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.pay_order.key-generator.type