Sharding-jdbc是在java代码层面实现分库分表,不需要额外的软件安装
关于分库分表阿里巴巴开发手册上有明确说明: 单表行数超过500万行或者单表容量超过2GB,才推荐进行分库分表 如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表
概念
垂直拆分
垂直分表
把表的一部分字段数据存到一张新表中
一张表的数据分到两个表中存储,由此提高IO效率
实现垂直分表不需要额外的组件实现,更多是数据库设计层面解决的问题
垂直分库
水平拆分
水平分库
水平分表
在同一个数据库中根据行数创建多个相同的表,这样一个表存放的数据就没那么大
SpringBoot整合Sharding-Jdbc使用
SpringBoot整合主要改配置文件就可以使用了
Maven依赖
使用springboot 2.2.4版本为例
使用mybatisplus 3.3.1整合sharding-jdbc 4.0.0-RC1,使用druid连接池
<properties><java.version>1.8</java.version><!-- MP版本配置 --><mybatis-plus-boot-starter.version>3.3.1</mybatis-plus-boot-starter.version><sharding-jdbc.version>4.0.0-RC1</sharding-jdbc.version><druid-version>1.1.20</druid-version></properties><dependencies><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>${sharding-jdbc.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid-version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- 定义mybatis-plus依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybatis-plus-boot-starter.version}</version></dependency></dependencies>
整合MybatisPlus注意事项
application.yml配置
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml
configuration:
# 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
map-underscore-to-camel-case: true
# 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
call-setters-on-nulls: false
POJO类注意点
比如我需要对course_1和course_2表进行操作
但是我只需要创建一个po类就行了,course_1和course_2都只对应一个CoursePO类
与yml配置文件配置的逻辑表对应,指定表名为course就行,虽然数据库中并没有名为course的表
@TableName("course")
public class CoursePO implements Serializable {
//...
}
在application.yml中要注意写上此配置
spring:
main:
# 一个实体类对应两张表,覆盖
allow-bean-definition-overriding: true
mapper.xml注意点
CoursePO类对应course_1和course_2两张表
操作时也只需要与yml配置文件对应,指定表名为course就行
<select id="findById" resultType="com.halayang.course.po.CoursePO">
select * from course where id = #{id}
</select>
水平分表实现
在一个数据库中根据策略将数据存放到结构相同的两个表中
demo设计:在本地名为sharding-learning数据库中创建两个结构一样的表course_1表和course_2表
application.yml配置
官方文档给的properties的配置,但是分库分表所要写的配置会很多,yml更有层次性,个人更喜欢yml
一定要注意层级!!!
# 水平分表
spring:
main:
# 一个实体类对应两张表,覆盖
allow-bean-definition-overriding: true
shardingsphere:
datasource:
# 配置数据源,给数据源起名称 可以起多个
names: m1
m1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/sharding-learning?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
props:
sql:
# 显示解析的sql
show: true
sharding:
tables:
course:
# 指定 course 表分布情况,配置表在哪个数据库里面,表名称都是什么 m1.course_1 , m1.course_2
actual-data-nodes: m1.course_$->{1..2}
key-generator:
column: id
# 主键id使用雪花算法,自动插入
type: SNOWFLAKE
table-strategy:
inline:
# 指定主键列命
sharding-column: id
# 根据id的奇偶性来确定存放到哪个表中
algorithm-expression: course_$->{id % 2 + 1}
水平分库实现
根据策略使数据存放到不同数据库的相同表中
demo设计:建两个数据库edu_db1和edu_db2,每个数据库都有course_1和course_2表
application.yml配置
在此将水平分表和水平分库同时使用
# 水平分库
spring:
main:
# 一个实体类对应两张表,覆盖
allow-bean-definition-overriding: true
shardingsphere:
datasource:
# 配置数据源,给数据源起名称 可以起多个
names: m1,m2
# 第一个数据源
m1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/edu_db1?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
# 第一个数据源
m2:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/edu_db2?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
props:
sql:
# 显示解析的sql
show: true
sharding:
# 所有表都按照此规则做分库
# default-database-strategy:
# inline:
# # 根据user_id奇偶数分库
# sharding-column: user_id
# algorithm-expression: m$->{user_id % 2}
tables:
# 指定表名
course:
# 在指定表下制定分库策略
database-strategy:
inline:
# 根据user_id奇偶数分库
sharding-column: user_id
algorithm-expression: m$->{user_id % 2 + 1}
# 指定数据库分库,以及数据库里表的分布
actual-data-nodes: m$->{1..2}.course_$->{1..2}
# 主键生成策略
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
# 指定分表策略
inline:
# 根据id奇偶数分表
algorithm-expression: course_$->{id % 2 + 1}
sharding-column: id
垂直分库实现
根据业务需求将不同的表存放在不同的数据库中
现有两个数据库edu_db1和edu_db2 新增一个t_user表只存放在edu_db1中 所以涉及到t_user表的操作时只需要访问edu_db1就行了 course_1和course_2的分库分表操作同上
application.yml配置
# 垂直分库
spring:
main:
# 一个实体类对应两张表,覆盖
allow-bean-definition-overriding: true
shardingsphere:
datasource:
# 配置数据源,给数据源起名称 可以起多个
names: m1,m2
# 第一个数据源
m1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/edu_db1?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
# 第一个数据源
m2:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/edu_db2?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
props:
sql:
# 显示解析的sql
show: true
sharding:
tables:
# 指定表名
course:
# 指定数据库分库,以及数据库里表的分布
actual-data-nodes: m$->{1..2}.course_$->{1..2}
# 主键生成策略
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
# 指定分表策略
inline:
sharding-column: id
# 根据id奇偶数分表
algorithm-expression: course_$->{id % 2 + 1}
# 指定t_user表
t_user:
# 指定user的库和表
actual-data-nodes: m1.t_user
# 主键生成策略
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
# 指定分表策略
inline:
# 指定库和表 不对此表做分表操作 配置比较简单
sharding-column: id
algorithm-expression: t_user
公共表配置
有些表数据变化不是很大,不需要进行分库分表策略
新增一个t_udict表作为公共表 对垂直分库的配置文件进行一些小改动,加一点配置
application.yml配置
# 垂直分库
spring:
main:
# 一个实体类对应两张表,覆盖
allow-bean-definition-overriding: true
shardingsphere:
datasource:
# 配置数据源,给数据源起名称 可以起多个
names: m1,m2
# 第一个数据源
m1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/edu_db1?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
# 第一个数据源
m2:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/edu_db2?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
props:
sql:
# 显示解析的sql
show: true
sharding:
tables:
# 指定表名
course:
# 指定数据库分库,以及数据库里表的分布
actual-data-nodes: m$->{1..2}.course_$->{1..2}
# 主键生成策略
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
# 指定分表策略
inline:
# 根据id奇偶数分表
algorithm-expression: course_$->{id % 2 + 1}
sharding-column: id
t_user:
# 指定user的库和表
actual-data-nodes: m1.t_user
# 主键生成策略
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
# 指定分表策略
inline:
# 指定库和表
sharding-column: id
algorithm-expression: t_user
# 公共表配置
t_udict:
# 指定数据库和表
actual-data-nodes: m1.t_udict
key-generator:
column: id
type: SNOWFLAKE
# 指定公共表
broadcast-tables: t_udict
读写分离实现
首先要对mysql进行主从复制的配置
https://www.yuque.com/kelisidiyanuodi/dttdng/unkied
搭建完成之后使用Sharding-jdbc实现读写分离的操作
开启两台虚拟机启动mysql服务 两个服务器上的mysql都有一个名为edu_db1的数据库 创建一个t_user表,对t_user表的操作实现读写分离
application.yml配置
# 读写分离配置
# select执行从库 insert update delete执行从库
spring:
main:
# 一个实体类对应两张表,覆盖
allow-bean-definition-overriding: true
shardingsphere:
datasource:
# 配置数据源,给数据源起名称 可以起多个
names: m1,s1
m1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://192.168.246.103:3306/edu_db1?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
# 第一个数据源
s1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://192.168.246.104:3306/edu_db1?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
props:
sql:
# 显示解析的sql
show: true
sharding:
master-slave-rules:
# 给数据库取个名字
edu_db1:
# 主库
master-data-source-name: m1
# 从库
slave-data-source-names: s1
tables:
t_user:
# 对主从库的表进行操作
actual-data-nodes: edu_db1.t_user
# 主键生成策略
key-generator:
column: id
type: SNOWFLAKE
table-strategy:
# 指定分表策略
inline:
# 指定库和表
sharding-column: id
algorithm-expression: t_user
待解决的问题
demo都是用阿里巴巴的druid连接池实现的
如果改为使用Hikari连接池就会启动报错
demo使用的sharding-jdbc版本是4.0.0-RC1,升级到4.0.0-RC2时启动报错 UnsatisfiedDependencyException
4.0.0-RC2时启动报错 解决方案
在上面的maven依赖中
删除druid starter依赖
解决自动配置依赖冲突
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-version}</version>
</dependency>
改用druid依赖即可
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid-version}</version>
</dependency>
HikariCP连接池 解决方案
只需要在application.yml配置文件中微调
在涉及数据库连接池的配置中只需要把url改成jdbc-url即可
在此放出hikari的一些配置
spring:
shardingsphere:
datasource:
# 配置数据源,给数据源起名称 可以起多个
names: m1,m2
# 第一个数据源
m1:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://localhost:3306/edu_db1?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
hikari:
connection-timeout: 30000
minimum-idle: 5
maximum-pool-size: 30
idle-timeout: 30000
max-lifetime: 120000
auto-commit: true
connection-test-query: SELECT 1
# 第二个数据源
m2:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://localhost:3306/edu_db2?useSSL=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=GMT%2B8
hikari:
connection-timeout: 30000
minimum-idle: 5
maximum-pool-size: 30
idle-timeout: 30000
max-lifetime: 120000
auto-commit: true
connection-test-query: SELECT 1
