分库分表是一种数据分片技术,将数据库中的数据按照一定规则划分到多个库和表中,以提高数据处理能力和存储效率。具体来说,分库是将数据按照一定规则分散到多个数据库中,每个数据库中存储部分数据;分表是将同一个表中的数据按照一定的规则划分到多个表中,每个表中存储部分数据。通过分库分表,可以将单个数据库的性能瓶颈分散到多个数据库和表中,提高了数据处理效率和存储容量。
水平分库分表:按照某种规则将原有的数据表(记录)划分到多个库(表)中,每个库(表)存储部分数据,避免单个库(表)承载过多数据而导致的性能压力,提高数据读写效率。
垂直分库分表:将一张大表按照表的列属性划分成多个小表,将不同的列分散到不同的表中。这种方式更加侧重于功能分离,各个小表负责自己的特定功能,可以更好的做到维护和管理。
分区:将数据按照某个字段进行分区,每个区域独立存储在不同的数据库或表中,这种方式更加关注数据的划分和分类,可以将大数据量的数据进行合理的存储和管理。
数据库主从复制:将读写分离,读操作负责从从库读取数据,写操作则由主库执行,这样可以大大减轻主库的负担,提高读性能和负载均衡。
反向代理:将请求分发到不同的数据库或表中,可以实现负载均衡和高可用性。
因为在实际业务应用中,大部分的业务需求达不到分库分表的级别,有的业务稍微复杂点可能分库就可以搞定,不需要分表,所以这里注释关闭掉了shardingsphere-jdbc分库分表和Seata分布式事务的配置,只保留了dynamic-datasource动态多数据源的配置,如果需要使用分表和分布式事务,那么把注释打开即可。
1、打开gitegg-platform-db中shardingsphere-jdbc的依赖注释
org.apache.shardingsphere
shardingsphere-jdbc-core-spring-boot-starter
org.apache.shardingsphere
shardingsphere-jdbc-core-spring-namespace
2、打开gitegg-platform-db中DynamicDataSourceProviderConfig.java的配置注释
@Configuration
@AutoConfigureBefore(DynamicDataSourceAutoConfiguration.class)
public class DynamicDataSourceProviderConfig {
@Resource
private DynamicDataSourceProperties properties;
/**
* shardingSphereDataSource
*/
@Lazy
@Resource(name = "shardingSphereDataSource")
private DataSource shardingSphereDataSource;
@Bean
public DynamicDataSourceProvider dynamicDataSourceProvider() {
Map datasourceMap = properties.getDatasource();
return new AbstractDataSourceProvider() {
@Override
public Map loadDataSources() {
Map dataSourceMap = createDataSourceMap(datasourceMap);
dataSourceMap.put("sharding", shardingSphereDataSource);
return dataSourceMap;
}
};
}
/**
* 将动态数据源设置为首选的
* 当spring存在多个数据源时, 自动注入的是首选的对象
* 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
*/
@Primary
@Bean
public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
dataSource.setPrimary(properties.getPrimary());
dataSource.setStrict(properties.getStrict());
dataSource.setStrategy(properties.getStrategy());
dataSource.setProvider(dynamicDataSourceProvider);
dataSource.setP6spy(properties.getP6spy());
dataSource.setSeata(properties.getSeata());
return dataSource;
}
}
3、修改配置文件shardingsphere-jdbc的分库分表规则
# shardingsphere 配置
shardingsphere:
props:
sql:
show: true
datasource:
common:
type: com.alibaba.druid.pool.DruidDataSource
validationQuery: SELECT 1 FROM DUAL
names: shardingorder0,shardingorder1
shardingorder0:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_order0?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&all owMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
shardingorder1:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_order1?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&all owMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
rules:
sharding:
tables:
t_mall_order:
actual-data-nodes: shardingorder$->{0..1}.t_mall_order$->{0..1}
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: database-inline
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline-order
key-generate-strategy:
column: id
key-generator-name: snowflake
t_mall_order_sku:
actual-data-nodes: shardingorder$->{0..1}.t_mall_order_sku$->{0..1}
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: database-inline
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline-order-sku
key-generate-strategy:
column: id
key-generator-name: snowflake
sharding-algorithms:
database-inline:
type: INLINE
props:
algorithm-expression: shardingorder$->{id % 2}
table-inline-order:
type: INLINE
props:
algorithm-expression: t_mall_order$->{id % 2}
table-inline-order-sku:
type: INLINE
props:
algorithm-expression: t_mall_order_sku$->{id % 2}
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 123
4、打开动态数据源的分布式事务配置
# 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭
seata: true
5、打开Seata本身的配置开关
seata:
enabled: true
6、完整Nacos配置文件
spring:
jackson:
time-zone: Asia/Shanghai
date-format: yyyy-MM-dd HH:mm:ss
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: 'http://127.0.0.1/gitegg-oauth/oauth/public_key'
autoconfigure:
# 动态数据源排除默认配置
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
# shardingsphere 配置
shardingsphere:
props:
sql:
show: true
datasource:
common:
type: com.alibaba.druid.pool.DruidDataSource
validationQuery: SELECT 1 FROM DUAL
names: shardingorder0,shardingorder1
shardingorder0:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_order0?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&all owMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
shardingorder1:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_order1?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&all owMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
rules:
sharding:
tables:
t_mall_order:
actual-data-nodes: shardingorder$->{0..1}.t_mall_order$->{0..1}
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: database-inline
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline-order
key-generate-strategy:
column: id
key-generator-name: snowflake
t_mall_order_sku:
actual-data-nodes: shardingorder$->{0..1}.t_mall_order_sku$->{0..1}
# 配置分库策略
databaseStrategy:
standard:
shardingColumn: id
shardingAlgorithmName: database-inline
table-strategy:
standard:
sharding-column: id
sharding-algorithm-name: table-inline-order-sku
key-generate-strategy:
column: id
key-generator-name: snowflake
sharding-algorithms:
database-inline:
type: INLINE
props:
algorithm-expression: shardingorder$->{id % 2}
table-inline-order:
type: INLINE
props:
algorithm-expression: t_mall_order$->{id % 2}
table-inline-order-sku:
type: INLINE
props:
algorithm-expression: t_mall_order_sku$->{id % 2}
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 123
datasource:
druid:
stat-view-servlet:
enabled: true
loginUsername: admin
loginPassword: 123456
dynamic:
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
strict: false
# 开启seata代理,开启后默认每个数据源都代理,如果某个不需要代理可单独关闭
seata: true
#支持XA及AT模式,默认AT
seata-mode: AT
druid:
initialSize: 1
minIdle: 3
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 30000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
# 打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: config,stat,slf4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;
# 合并多个DruidDataSource的监控数据
useGlobalDataSourceStat: true
datasource:
master:
url: jdbc:mysql://127.0.0.1/gitegg_cloud?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&all owMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
mall_user:
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_user?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
mall_goods:
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_goods?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
mall_order:
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_order?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
mall_pay:
url: jdbc:mysql://127.0.0.1/gitegg_cloud_mall_pay?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&alowMultiQueries=true&serverTimezone=Asia/Shanghai
username: root
password: root
cloud:
sentinel:
filter:
enabled: true
transport:
port: 8719
dashboard: 127.0.0.1:8086
eager: true
datasource:
ds2:
nacos:
data-type: json
server-addr: 127.0.0.1:8848
dataId: ${spring.application.name}-sentinel
groupId: DEFAULT_GROUP
rule-type: flow
redis:
database: 1
host: 127.0.0.1
port: 6312
password: myredis4Hisc
ssl: false
timeout: 2000
redisson:
config: |
singleServerConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
password: myredis4Hisc
subscriptionsPerConnection: 5
clientName: null
address: "redis://127.0.0.1:6312"
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
connectionMinimumIdleSize: 32
connectionPoolSize: 64
database: 0
dnsMonitoringInterval: 5000
threads: 0
nettyThreads: 0
codec: ! {}
"transportMode":"NIO"
#业务系统相关初始化参数
system:
#登录密码默认最大尝试次数
maxTryTimes: 5
#不需要验证码登录的最大次数
maxNonCaptchaTimes: 2
#注册用户默认密码
defaultPwd: 12345678
#注册用户默认角色ID
defaultRoleId: 4
#注册用户默认组织机构ID
defaultOrgId: 79
#不需要数据权限过滤的角色key
noDataFilterRole: DATA_NO_FILTER
#AccessToken过期时间(秒)默认为2小时
accessTokenExpiration: 60
#RefreshToken过期时间(秒)默认为24小时
refreshTokenExpiration: 300
feign:
hystrix:
enabled: false
compression:
# 配置响应 GZIP 压缩
response:
enabled: true
# 配置请求 GZIP 压缩
request:
enabled: true
# 支持压缩的mime types
mime-types: text/xml,application/xml,application/json
# 配置压缩数据大小的最小阀值,默认 2048
min-request-size: 2048
client:
config:
default:
connectTimeout: 8000
readTimeout: 8000
loggerLevel: FULL
#Ribbon配置
ribbon:
#请求连接的超时时间
ConnectTimeout: 50000
#请求处理/响应的超时时间
ReadTimeout: 50000
#对所有操作请求都进行重试,如果没有实现幂等的情况下是很危险的,所以这里设置为false
OkToRetryOnAllOperations: false
#切换实例的重试次数
MaxAutoRetriesNextServer: 5
#当前实例的重试次数
MaxAutoRetries: 5
#负载均衡策略
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
#Sentinel端点配置
management:
endpoints:
web:
exposure:
include: '*'
mybatis-plus:
mapper-locations: classpath*:/com/gitegg/*/*/mapper/*Mapper.xml
typeAliasesPackage: com.gitegg.*.*.entity
global-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: 2
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: 2
#驼峰下划线转换
db-column-underline: true
#刷新mapper 调试神器
refresh-mapper: true
#数据库大写下划线转换
#capital-mode: true
#逻辑删除配置
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 多租户配置
tenant:
# 是否开启租户模式
enable: true
# 需要排除的多租户的表
exclusionTable:
- "t_sys_district"
- "t_sys_tenant"
- "t_sys_role"
- "t_sys_resource"
- "t_sys_role_resource"
- "oauth_client_details"
# 租户字段名称
column: tenant_id
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: gitegg_seata_tx_group
# 一定要是false
enable-auto-data-source-proxy: false
service:
vgroup-mapping:
#key与上面的gitegg_seata_tx_group的值对应
gitegg_seata_tx_group: default
config:
type: nacos
nacos:
namespace:
serverAddr: 127.0.0.1:8848
group: SEATA_GROUP
userName: "nacos"
password: "nacos"
registry:
type: nacos
nacos:
#seata服务端(TC)在nacos中的应用名称
application: seata-server
server-addr: 127.0.0.1:8848
namespace:
userName: "nacos"
password: "nacos"
#验证码配置
captcha:
#验证码的类型 sliding: 滑动验证码 image: 图片验证码
type: sliding
aj:
captcha:
#缓存local/redis...
cache-type: redis
#local缓存的阈值,达到这个值,清除缓存
#cache-number=1000
#local定时清除过期缓存(单位秒),设置为0代表不执行
#timing-clear=180
#验证码类型default两种都实例化。
type: default
#汉字统一使用Unicode,保证程序通过@value读取到是中文,在线转换 https://tool.chinaz.com/tools/unicode.aspx 中文转Unicode
#右下角水印文字(我的水印)
water-mark: GitEgg
#右下角水印字体(宋体)
water-font: 宋体
#点选文字验证码的文字字体(宋体)
font-type: 宋体
#校验滑动拼图允许误差偏移量(默认5像素)
slip-offset: 5
#aes加密坐标开启或者禁用(true|false)
aes-status: true
#滑动干扰项(0/1/2) 1.2.2版本新增
interference-options: 2
# 接口请求次数一分钟限制是否开启 true|false
req-frequency-limit-enable: true
# 验证失败5次,get接口锁定
req-get-lock-limit: 5
# 验证失败后,锁定时间间隔,s
req-get-lock-seconds: 360
# get接口一分钟内请求数限制
req-get-minute-limit: 30
# check接口一分钟内请求数限制
req-check-minute-limit: 60
# verify接口一分钟内请求数限制
req-verify-minute-limit: 60
#SMS短信通用配置
sms:
#手机号码正则表达式,为空则不做验证
reg:
#负载均衡类型 可选值: Random、RoundRobin、WeightRandom、WeightRoundRobin
load-balancer-type: Random
web:
#启用web端点
enable: true
#访问路径前缀
base-path: /commons/sms
verification-code:
#验证码长度
code-length: 6
#为true则验证失败后删除验证码
delete-by-verify-fail: false
#为true则验证成功后删除验证码
delete-by-verify-succeed: true
#重试间隔时间,单位秒
retry-interval-time: 60
#验证码有效期,单位秒
expiration-time: 180
#识别码长度
identification-code-length: 3
#是否启用识别码
use-identification-code: false
redis:
#验证码业务在保存到redis时的key的前缀
key-prefix: VerificationCode
# 网关放行设置 1、whiteUrls不需要鉴权的公共url,白名单,配置白名单路径 2、authUrls需要鉴权的公共url
oauth-list:
whiteUrls:
- "/gitegg-oauth/login/phone"
- "/gitegg-oauth/login/qr"
- "/gitegg-oauth/oauth/token"
- "/gitegg-oauth/oauth/public_key"
- "/gitegg-oauth/oauth/captcha/type"
- "/gitegg-oauth/oauth/captcha"
- "/gitegg-oauth/oauth/captcha/check"
- "/gitegg-oauth/oauth/captcha/image"
- "/gitegg-oauth/oauth/sms/captcha/send"
authUrls:
- "/gitegg-oauth/oauth/user/info"
- "/gitegg-oauth/oauth/logout"
- "/gitegg-mall-goods/mall/goods/stock/reduce"
- "/gitegg-mall-goods/mall/goods/list/by/id"
- "/gitegg-mall-user/mall/user/account/deduction"
- "/gitegg-mall-pay/mall/pay/pay"
- "/gitegg-mall-order/mall/order/order"
分库分表是一种数据库优化方案,它可以提升数据库的性能、可扩展性和可靠性。主要原因如下:
提升数据库性能:当数据表过于庞大时,查询效率和执行效率会受到很大影响,分库分表可以将数据分散到多个物理节点上,从而提高数据库性能。
实现数据分布式存储:对于大型企业级应用,单一数据库可能无法满足数据处理和存储的需求,分库分表可以将数据分散到多个物理节点上,实现数据分布式存储。
支持高并发访问:分库分表可以在多个物理节点上同时进行数据读写操作,从而支持高并发访问,解决单一数据库可能因为过度压力而导致的性能问题。
支持快速扩展和容灾恢复:分库分表可以通过增加或删除物理节点来快速扩展或缩小数据库的容量,同时通过数据备份和恢复来实现容灾恢复,提高数据库的可靠性。