# SpringBoot分库分表
# ShardingJDBC基于Mybatis单库分表
# 引入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
# yml配置
spring:
shardingsphere:
datasource:
names: ds # 数据源名称,唯一标识
ds:
type: com.zaxxer.hikari.HikariDataSource # 数据源类型
driver-class-name: com.mysql.cj.jdbc.Driver # 驱动名称
jdbc-url: jdbc:mysql://localhost:3306/test_db_sharding?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&characterEncoding=utf8
username: root
password: 123456
sharding:
tables:
tb_user: # 要分库分表的名称
actual-data-nodes: ds.tb_user_$->{0..1} # 数据节点 tb_user_0 tb_user_1
table-strategy: # 分表策略
inline: # 内联方式
sharding-column: id # 切片的列
algorithm-expression: tb_user_$->{id % 2} # 奇数在tb_user_1 偶数在tb_user_0
key-generator: # 主键生成策略
column: id # 主键列名
type: SNOWFLAKE
props:
worker: # 工作节点为123
id: 123
binding-tables: tb_user
mybatis:
type-aliases-package: #实体对象包全限定名
configuration:
cache-enabled: true
use-generated-keys: true
default-executor-type: REUSE
use-actual-param-name: true
# 注意事项
- 数据分片后,原有的数据库自动增长ID以及ORM层框架的配置不能再使用
- 使用SNOWFLAKE 雪花算法,64为LONG类型,所以需要设置相关字段为BIGINT
- 注意项目中springboot、jdk的版本号
# ShardingJDBC基于JPA单库分表
# 引入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.github.wenhao</groupId>
<artifactId>jpa-spec</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
# yml配置
# sharding部分配置和前文mybatis方式相同
jpa:
open-in-view: false # 每个请求处理完毕关闭数据库连接
generate-ddl: false # 一般在开发阶段使用,根据entity生成数据库的ddl
show-sql: false # 控制台不显示sql语句
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect # 数据库方言
format_sql: true
use-new-id-generator-mappings: false # 新的主键映射策略
# 注意事项
- jpa方式要使用@Table标注表名 @Repository标注dao
# ShardingJSBD基于jpa读写分离
# 读写分离介绍
设计目标:让使用方像使用一个数据库一样使用主从数据库集群
读写分离则是根据SQL语义的分析,将读操作和写操作分别路由至主库与从库。
读写分离可以提升系统的吞吐量和可用性,但也带来了数据不一致的问题
# 引入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.github.wenhao</groupId>
<artifactId>jpa-spec</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
# yml配置
spring:
shardingsphere:
datasource:
names: master,slave0 # 定义多个数据源
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test_db_sharding_master?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&characterEncoding=utf8
username: test
password: test
slave0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test_db_sharding_slave0?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&characterEncoding=utf8
username: test
password: test
sharding: # 分片
tables:
tb_user:
database-strategy:
inline:
sharding-column: id
algorithm-expression: master
key-generator:
column: id
type: SNOWFLAKE
props:
worker:
id: 123
# 其他表
master-slave: #主从配置
name: ms
load-balance-algorithm-type: round_robin # 负载均衡算法为轮询
master-data-source-name: master # 主数据库名称
slave-data-source-names: slave0 # 从数据库名称
props:
sql:
show: true
jpa:
open-in-view: false
generate-ddl: false
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.MySQLDialect
format_sql: true
use-new-id-generator-mappings: false
# 注意事项
- 主库和从库的数据同步不是shardingJDBC做的,需要自行同步
- 查询操作会发生在从库,修改、添加,操作会发生在主库
原文链接 https://www.pdai.tech/md/spring/springboot/springboot-x-mysql-shardingjdbc-jpa-masterslave.html
# ShardingJDBC基于JPA的DB隔离
# 知识准备
逻辑表:水平拆分的数据库的相同逻辑和数据结构表的总称。例如订单数据有10张表,分别是t_order_0到t_order_9,逻辑表名为t_order
真实表:分片数据库中真实存在的物理表,t_order_0到t_order_9
数据节点: 数据源名称和数据表,例如ds_0.t_order_0
绑定表:分片规则一致的主表和子表,如t_order和t_order_item,均按照order_id分片
- 绑定表之间的多表关联查询不会出现笛卡尔积
广播表: 分布式计算中,将小表的副本发送到集群的每个节点,以便提高访问效率。
分片键:用于分片的数据库字段
分片算法:精确分片算法(单字段)、范围分片算法、复合分片算法(多字段)、Hint分片算法
分片策略:标准分片策略、复合分片策略、行表达式分片策略(groovy表达式)、Hint分片策略
# yml配置
shardingsphere:
datasource:
names: tenant-a,tenant-b
tenant-a:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test_db_tenant_a?allowPublicKeyRetrieval=true&useSSL=false&autoReconnect=true&characterEncoding=utf8
username: root
password: 123456
tenant-b:
...
sharding:
default-database-strategy:
hint:
algorithm-class-name:
# hint算法全限定类名
tables:
tb_user:
actual-data-nodes: tenant-${['a','b']}.tb_user
key-generator:
...
tb_role:
actual-data-nodes: tenant-${['a','b']}.tb_role
key-generator:
...
tb_user_role:
actual-data-nodes: tenant-${['a','b']}.tb_user_role
key-generator:
...
binding-tables: tb_user,tb_role,tb_user_role
props:
sql:
show: true
# 使用
@Aspect
@Order(1)
@Component
public class TenantDatasourceAspect {
/**
* 定义切点.
*/
@Pointcut("execution(* tech.pdai.springboot.shardingjdbc.jpa.tenant.dbhint.dao.*.*(..))")
public void useTenantDSPointCut() {
// no impl
}
// 前置逻辑
@Before("useTenantDSPointCut()")
public void doDs0Before() {
HintManager.clear();
HintManager hintManager = HintManager.getInstance();
// 实际环境将client信息放在xxxContext中(由ThreadLocal承接),并通过client-id来获取tenant.
// 这里为了方便演示,只是使用了tenant-a
hintManager.setDatabaseShardingValue("tenant-a");
}
// 后置逻辑
@After("useTenantDSPointCut()")
public void doDs0after() {
HintManager.clear();
}
}