什么是 ShardingSphere?
1、一套開源的分布式數據庫中間件解決方案
2、有三個產品:Sharding-JDBC 和 Sharding-Proxy
3、定位為關系型數據庫中間件,合理在分布式環境下使用關系型數據庫操作
什么是分庫分表
1、數據庫數據量不可控的,隨着時間和業務發展,造成表里面數據越來越多,如果再去對數據庫表 curd 操作時候,造成性能問題。
2、方案 1:從硬件上
3、方案 2:分庫分表
* 為了解決由於數據量過大而造成數據庫性能降低問題。
|

分庫分表的方式
1、分庫分表有兩種方式:垂直切分和水平切分
2、垂直切分:垂直分表和垂直分庫
3、水平切分:水平分表和水平分庫
4、垂直分表
(1)操作數據庫中某張表,把這張表中一部分字段數據存到一張新表里面,再把這張表另一
部分字段數據存到另外一張表里面
|

5、垂直分庫
(1)把單一數據庫按照業務進行划分,專庫專表

6、水平分庫

7、水平分表

分庫分表應用和問題
1、應用
(1)在數據庫設計時候考慮垂直分庫和垂直分表
(2)隨着數據庫數據量增加,不要馬上考慮做水平切分,首先考慮緩存處理,讀寫分離,使用索引等等方式,如果這些方式不能根本解決問題了,再考慮做水平分庫和水平分表
2、分庫分表問題
(1)跨節點連接查詢問題(分頁、排序)
(2)多數據源管理問題
|
Sharding-JDBC 簡介
1、是輕量級的 java 框架,是增強版的 JDBC 驅動
2、Sharding-JDBC
(1)主要目的是:簡化對分庫分表之后數據相關操作
|
Sharding-JDBC 實現水平分表
(4)引入需要的依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2、按照水平分表的方式,創建數據庫和數據庫表
(1)創建數據庫 course_db
(2)在數據庫創建兩張表 course_1 和 course_2
(3)約定規則:如果添加課程 id 是偶數把數據添加 course_1,如果奇數添加到 course_2

3、編寫代碼實現對分庫分表后數據的操作
1)創建實體類,mapper

4、配置 Sharding-JDBC 分片策略
(1)在項目 application.properties 配置文件中進行配置

# shardingjdbc 分片策略 # 配置數據源,給數據源起名稱 spring.shardingsphere.datasource.names=m1 # 一個實體類對應兩張表,覆蓋 spring.main.allow-bean-definition-overriding=true #配置數據源具體內容,包含連接池,驅動,地址,用戶名和密碼 spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/course_db?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=root
#指定 course 表分布情況,配置表在哪個數據庫里面,表名稱都是什么 m1.course_1 ,m1.course_2
spring.shardingsphere.sharding.tables.course.actual-data-nodes=m1.course_$->{1..2}
# 指定 course 表里面主鍵 cid 生成策略 SNOWFLAKE
spring.shardingsphere.sharding.tables.course.key-generator.column=cid
spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
# 指定分片策略 約定 cid 值偶數添加到 course_1 表,如果 cid 是奇數添加到 course_2表
spring.shardingsphere.sharding.tables.course.table-strategy.inline.sharding-column=cid
spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cid % 2 + 1}
# 打開 sql 輸出日志
spring.shardingsphere.props.sql.show=true
5、編寫測試代碼
@RunWith(SpringRunner.class) @SpringBootTest public class ShardingjdbcdemoApplicationTests { //注入 mapper @Autowired private CourseMapper courseMapper; //添加課程的方法 @Test public void addCourse() { for(int i=1;i<=10;i++) { Course course = new Course(); course.setCname("java"+i); course.setUserId(100L); course.setCstatus("Normal"+i); courseMapper.insert(course); } } //查詢課程的方法 @Test public void findCourse() { QueryWrapper<Course> wrapper = new QueryWrapper<>(); wrapper.eq("cid",465114665106538497L); Course course = courseMapper.selectOne(wrapper); System.out.println(course); }
}
(1)上面測試代碼執行,報錯了

(2)解決方案,在配置文件中添加一行配置
# 一個實體類對應兩張表,覆蓋 spring.main.allow-bean-definition-overriding=true
Sharding-JDBC 實現水平分庫
1、需求分析

2、創建數據庫和表

3、在 SpringBoot 配置文件配置數據庫分片規則
# shardingjdbc 分片策略 # 配置數據源,給數據源起名稱, # 水平分庫,配置兩個數據源 spring.shardingsphere.datasource.names=m1,m2 # 一個實體類對應兩張表,覆蓋 spring.main.allow-bean-definition-overriding=true #配置第一個數據源具體內容,包含連接池,驅動,地址,用戶名和密碼 spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/edu_db_1?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.m1.username=root spring.shardingsphere.datasource.m1.password=root
#配置第二個數據源具體內容,包含連接池,驅動,地址,用戶名和密碼 spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/edu_db_2?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.m2.username=root spring.shardingsphere.datasource.m2.password=root
#指定數據庫分布情況,數據庫里面表分布情況 # m1 m2 course_1 course_2 spring.shardingsphere.sharding.tables.course.actual-data-nodes=m$->{1..2}.course_$->{1..2}
# 指定 course 表里面主鍵 cid 生成策略 SNOWFLAKE spring.shardingsphere.sharding.tables.course.key-generator.column=cid spring.shardingsphere.sharding.tables.course.key-generator.type=SNOWFLAKE
# 指定表分片策略 約定 cid 值偶數添加到 course_1 表,如果 cid 是奇數添加到course_2 表 spring.shardingsphere.sharding.tables.course.table-strategy.inline.shardingcolumn=cid spring.shardingsphere.sharding.tables.course.table-strategy.inline.algorithmexpression=course_$->{cid % 2 + 1}
# 指定數據庫分片策略 約定 user_id 是偶數添加 m1,是奇數添加 m2 #spring.shardingsphere.sharding.default-database-strategy.inline.shardingcolumn=user_id #spring.shardingsphere.sharding.default-database-strategy.inline.algorithm- expression=m$->{user_id % 2 + 1} spring.shardingsphere.sharding.tables.course.databasestrategy.inline..sharding-column=user_id spring.shardingsphere.sharding.tables.course.databasestrategy.inline.algorithm-expression=m$->{user_id % 2 + 1} # 打開 sql 輸出日志 spring.shardingsphere.props.sql.show=tru
4、編寫測試方法
//======================測試水平分庫===================== //添加操作 @Test public void addCourseDb() { Course course = new Course(); course.setCname("javademo1"); //分庫根據 user_id course.setUserId(111L); course.setCstatus("Normal1"); courseMapper.insert(course); } //查詢操作 @Test public void findCourseDb() { QueryWrapper<Course> wrapper = new QueryWrapper<>(); //設置 userid 值 wrapper.eq("user_id",100L); //設置 cid 值 wrapper.eq("cid",465162909769531393L); Course course = courseMapper.selectOne(wrapper); System.out.println(course); }
Sharding-JDBC 實現垂直分庫
1、需求分析

2、創建數據庫和表

3、編寫操作代碼
(1)創建 user 實體類和 mapper
@Data @TableName(value = "t_user") //指定對應表 public class User { private Long userId; private String username; private String ustatus; }
(2)配置垂直分庫策略
* 在 application.properties 進行配置 # shardingjdbc 分片策略 # 配置數據源,給數據源起名稱, # 水平分庫,配置兩個數據源 spring.shardingsphere.datasource.names=m1,m2,m0 # 一個實體類對應兩張表,覆蓋 spring.main.allow-bean-definition-overriding=true
#配置第一個數據源具體內容,包含連接池,驅動,地址,用戶名和密碼 spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.m1.url=jdbc:mysql://localhost:3306/edu_db_1?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.m1.username=root spring.shardingsphere.datasource.m1.password=root
#配置第二個數據源具體內容,包含連接池,驅動,地址,用戶名和密碼 spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.m2.url=jdbc:mysql://localhost:3306/edu_db_2?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.m2.username=root spring.shardingsphere.datasource.m2.password=root #配置第三個數據源具體內容,包含連接池,驅動,地址,用戶名和密碼 spring.shardingsphere.datasource.m0.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.m0.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.m0.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.m0.username=root spring.shardingsphere.datasource.m0.password=root
# 配置 user_db 數據庫里面 t_user 專庫專表 spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{0}.t_user
# 指定 course 表里面主鍵 cid 生成策略 SNOWFLAKE spring.shardingsphere.sharding.tables.t_user.key-generator.column=user_id spring.shardingsphere.sharding.tables.t_user.key-generator.type=SNOWFLAKE
# 指定表分片策略 約定 cid 值偶數添加到 course_1 表,如果 cid 是奇數添加到course_2 表 spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.shardingcolumn=user_id spring.shardingsphere.sharding.tables.t_user.table-strategy.inline.algorithmexpression=t_user
(
3)編寫測試代碼
//注入 user 的 mapper @Autowired private UserMapper userMapper; //======================測試垂直分庫================== //添加操作 @Test public void addUserDb() { User user = new User(); user.setUsername("lucy"); user.setUstatus("a"); userMapper.insert(user); }
Sharding-JDBC 操作公共表
1、公共表
(1)存儲固定數據的表,表數據很少發生變化,查詢時候經常進行關聯
(2)在每個數據庫中創建出相同結構公共表
2、在多個數據庫都創建相同結構公共表
|

3、在項目配置文件 application.properties 進行公共表配置
# 配置公共表 spring.shardingsphere.sharding.broadcast-tables=t_udict spring.shardingsphere.sharding.tables.t_udict.key-generator.column=dictid spring.shardingsphere.sharding.tables.t_udict.key-generator.type=SNOWFLAKE
4、編寫測試代碼
(1)創建新實體類和 mapper
@Data @TableName(value = "t_udict") public class Udict { private Long dictid; private String ustatus; private String uvalue; }
(2)編寫添加和刪除方法進行測試
@Autowired private UdictMapper udictMapper; //======================測試公共表=================== //添加操作 @Test public void addDict() { Udict udict = new Udict(); udict.setUstatus("a"); udict.setUvalue("已啟用"); udictMapper.insert(udict); } //刪除操作 @Test public void deleteDict() { QueryWrapper<Udict> wrapper = new QueryWrapper<>(); //設置 userid 值 wrapper.eq("dictid",465191484111454209L); udictMapper.delete(wrapper); }
Sharding-JDBC 實現讀寫分離
1、讀寫分離概念
為了確保數據庫產品的穩定性,很多數據庫擁有雙機熱備功能,也就是,第一台數據庫服務器,是對外提供增刪改業務的生成服務器,第二台數據庫服務器,主要進行讀的操作。
原理:讓主數據庫(master)處理事務性增、改、刪操作,而從數據庫(slave)處理select查詢操作。

讀寫分離原理:

Sharding-JDBC 通過 sql 語句語義分析,實現讀寫分離過程,不會做數據同步
2、MySQL 配置讀寫分離
第一步 創建兩個 MySQL 數據庫服務,並且啟動兩個 MySQL 服務
(1)復制之前 MySQL 目錄

(2)修改復制之后配置文件

⚫ 修改端口號,文件路徑
⚫ 需要把數據文件目錄再復制一份

(3)把復制修改之后從數據庫在 windows 安裝服務
* 使用命令: mysqld install mysqls1 --defaults-file="D:\Program Files\MySQL\MySQLServer-s1\my.ini"

因為從庫是從主庫復制過來的,因此里面的數據完全一致,可使用原來的賬號、密碼登錄
第二步 配置 MySQL 主從服務器
(1)在主服務器配置文件 主庫my.ini文件
[mysqld]
#開啟日志 log‐bin = mysql‐bin #設置服務id,主從不能一致 server‐id = 1
#設置需要同步的數據庫 binlog‐do‐db=user_db #屏蔽系統庫同步 binlog‐ignore‐db=mysql binlog‐ignore‐db=information_schema binlog‐ignore‐db=performance_schema
(2)在從服務器配置文件 從庫my.ini文件
[mysqld] #開啟日志 log‐bin = mysql‐bin #設置服務id,主從不能一致 server‐id = 2
#設置需要同步的數據庫 replicate_wild_do_table=user_db.% #屏蔽系統庫同步 replicate_wild_ignore_table=mysql.% replicate_wild_ignore_table=information_schema.% replicate_wild_ignore_table=performance_schema.%
(3)把主和從服務器重啟
第三步 創建用於主從復制的賬號
#切換至主庫bin目錄,登錄主庫 mysql ‐h localhost ‐uroot ‐p #授權主備復制專用賬號 GRANT REPLICATION SLAVE ON *.* TO 'db_sync'@'%' IDENTIFIED BY 'db_sync'; #刷新權限 FLUSH PRIVILEGES;
#確認位點 記錄下文件名以及位點
show master status;

第四步 主從數據同步設置
#切換至從庫bin目錄,登錄從庫 mysql ‐h localhost ‐P3307 ‐uroot ‐p
#先停止同步 STOP SLAVE;
#修改從庫指向到主庫,使用上一步記錄的文件名以及位點 CHANGE MASTER TO master_host = 'localhost', master_user = 'db_sync', master_password = 'db_sync', master_log_file = 'mysql-bin.000177', master_log_pos = 107;
#啟動同步 START SLAVE;
#查看Slave_IO_Runing和Slave_SQL_Runing字段值都為Yes,表示同步配置成功。如果不為Yes,請排 查相關異常。 show slave status
3、Sharding-JDBC 操作
(1)配置讀寫分離策略
# user_db 從服務器 spring.shardingsphere.datasource.s0.type=com.alibaba.druid.pool.DruidDataSource spring.shardingsphere.datasource.s0.driver-class-name=com.mysql.cj.jdbc.Driver spring.shardingsphere.datasource.s0.url=jdbc:mysql://localhost:3307/user_db?serverTimezone=GMT%2B8 spring.shardingsphere.datasource.s0.username=root spring.shardingsphere.datasource.s0.password=root
# 主庫從庫邏輯數據源定義 ds0 為 user_db spring.shardingsphere.sharding.master-slave-rules.ds0.master-data-sourcename=m0 spring.shardingsphere.sharding.master-slave-rules.ds0.slave-data-sourcenames=s0
# 配置 user_db 數據庫里面 t_user 專庫專表 #spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=m$->{0}.t_user
# t_user 分表策略,固定分配至 ds0 的 t_user 真實表 spring.shardingsphere.sharding.tables.t_user.actual-data-nodes=ds0.t_user
(2)編寫測試代碼
//添加操作 @Test public void addUserDb() { User user = new User(); user.setUsername("lucymary"); user.setUstatus("a"); userMapper.insert(user); } //查詢操作 @Test public void findUserDb() { QueryWrapper<User> wrapper = new QueryWrapper<>(); //設置 userid 值 wrapper.eq("user_id",465508031619137537L); User user = userMapper.selectOne(wrapper); System.out.println(user); }
Sharding-Proxy 簡介
1、定位為透明的數據庫代理端

2
、Sharding-Proxy 獨立應用,需要安裝服務,進行分庫分表或者讀寫分離配置,啟動
使用
3、安裝
(1)下載安裝軟件

(2)把下載之后壓縮文件,解壓,啟動 bin 目錄啟動文件就可以了

Sharding-Proxy 配置(分表)
1、進入 conf 目錄,修改文件 server.yaml,去掉兩段內容注釋,打開即可

2、進入 conf 目錄,修改 config-sharding.yaml

(
1)復制 mysql 驅動 jar 包到 lib 目錄

(2)配置分庫分表規則
schemaName: sharding_db dataSources: ds_0: url: jdbc:mysql://127.0.0.1:3306/edu_1?serverTimezone=UTC&useSSL=false username: root password: root connectionTimeoutMilliseconds: 30000 idleTimeoutMilliseconds: 60000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 shardingRule: tables: t_order: actualDataNodes: ds_${0}.t_order_${0..1} tableStrategy: inline: shardingColumn: order_id algorithmExpression: t_order_${order_id % 2} keyGenerator: type: SNOWFLAKE column: order_id bindingTables: - t_order defaultDatabaseStrategy: inline: shardingColumn: user_id algorithmExpression: ds_${0} defaultTableStrategy: none:
3、啟動 Sharding-Proxy 服務
(1)Sharding-Proxy 默認端口號 3307
4、通過 Sharding-Proxy 啟動端口進行連接
(1)打開 cmd 窗口連接 Sharding-Proxy,連接方式和連接 mysql 一樣的

(2)進行 sql 命令操作看到只有一個庫

(3)在 sharding_db 數據庫創建表

(4)向表添加一條記錄
5、回到本地 3306 端口實際數據庫中,看到已經創建好了表和添加數據
Sharding-Proxy 配置(分庫)

2、找到 conf 目錄,config-sharding.yaml
schemaName: sharding_db dataSources: ds_0: url: jdbc:mysql://127.0.0.1:3306/edu_db_1?serverTimezone=UTC&useSSL=false username: root password: root connectionTimeoutMilliseconds: 30000 idleTimeoutMilliseconds: 60000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 ds_1: url: jdbc:mysql://127.0.0.1:3306/edu_db_2?serverTimezone=UTC&useSSL=false username: root
password: root
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
shardingRule:
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${1..2}
tableStrategy:
inline:
shardingColumn: order_id
algorithmExpression: t_order_${order_id % 2 + 1}
keyGenerator:
type: SNOWFLAKE
column: order_id
bindingTables:
- t_order
defaultDatabaseStrategy:
inline:
shardingColumn: user_id
algorithmExpression: ds_${user_id % 2}
defaultTableStrategy:
none:
3、啟動 Sharding-Proxy 服務

4、打開 cmd 倉庫,連接 Sharding-Proxy 服務

(1)創建數據庫表,向表添加記錄

(2)連接本地 3306 的 MySql 數據庫服務器,表已經創建出來,表里面有數據

Sharding-Proxy 配置(讀寫分離)
1、創建三個數據

2、修改 conf 里面配置文件,config-master-slave.yaml
schemaName: master_slave_db dataSources: master_ds: url: jdbc:mysql://127.0.0.1:3306/demo_ds_master?serverTimezone=UTC&useSSL=false username: root password: root connectionTimeoutMilliseconds: 30000 idleTimeoutMilliseconds: 60000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 slave_ds_0: url: jdbc:mysql://127.0.0.1:3306/demo_ds_slave_0?serverTimezone=UTC&useSSL=false username: root password: root connectionTimeoutMilliseconds: 30000 idleTimeoutMilliseconds: 60000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 slave_ds_1: url: jdbc:mysql://127.0.0.1:3306/demo_ds_slave_1?serverTimezone=UTC&useSSL=false username: root password: root connectionTimeoutMilliseconds: 30000 idleTimeoutMilliseconds: 60000 maxLifetimeMilliseconds: 1800000 maxPoolSize: 50 masterSlaveRule: name: ms_ds masterDataSourceName: master_ds slaveDataSourceNames: - slave_ds_0 - slave_ds_1
3、啟動 Sharding-Proxy 服務

4、通過 cmd 連接 Sharding-Proxy,進行創建表和添加記錄操作

(1)在主數據庫和從數據庫里面,都創建數據庫表
(2)向表添加記錄,不指定向哪個庫添加
* 把添加數據添加到主數據庫里面
