系统采用mysql数据库,技术框架采用基于springboot的springcloud,持久层采用jpa,数据库连接池阿里druid
随着最近系统用户量增加到500万,等各系统用户过来后会超过2000万,这个时候随着用户表数据量的增加,
用户表查询效率 低下。这个时候未雨绸缪,开始准备分库分表的准备,采用分布式数据库中间件,选择了sharding spshare,
这篇文章主要是用到了sharding-jdbc进行分库分表,我们用户人数预计最高2000万,我们采用的是分库单表方案,即6个库,一个单表
1我选用的是基于springboot的配置规则,本文省略druid的配置
首先需要引入依赖
UTF-8
UTF-8
1.8
4.0.0-RC1
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
${sharding-sphere.version}
org.apache.shardingsphere
sharding-jdbc-spring-namespace
${sharding-sphere.version}
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
5.1.47
com.alibaba
druid
1.1.16
com.alibaba
fastjson
1.2.47
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
commons-beanutils
commons-beanutils
1.9.4
2 实体 user 和实体 address 表 user表主键sid也是用户的唯一id,最开始系统采用的sid用36位uuid去掉下划线后使用。现在先不评论uuid优缺点,先实现uuid作为分表字段。实现分库分表功能。
package com.bmw.cop.user.entity;
import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name ="sys_user")
@Data
@EntityListeners(AuditingEntityListener.class)
public class User implements Serializable {
/**
* sid 用户ID
*/
@Id
@Column(name = "sid")
private String sid;
/**
* 手机号
*/
@Column(name = "mobile")
private String mobile;
。。。。。。
}
@Entity
@Data
@Table(name = "address")
@EntityListeners(AuditingEntityListener.class)
public class UserAddress implements Serializable {
@Id
@Column(name = "address_id")
private String addressId;
@Column(name = "street")
private String street;
@Column(name = "sid")
private String sid;
。。。。。。。。。
}
3 开始配置文件 application.properties 通过分片类实现分6个库单表(如果需要多表,自行修改配置即可满足)
server.port=8072
#jpa配置
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#datasource-name
spring.shardingsphere.datasource.names=ds0,ds1,ds2,ds3,ds4,ds5
#配置数据源
spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost:3306/ds0?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=15000&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=
spring.shardingsphere.datasource.ds1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds1.url=jdbc:mysql://localhost:3306/ds1?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=15000&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=
spring.shardingsphere.datasource.ds2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds2.url=jdbc:mysql://localhost:3306/ds2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=15000&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds2.username=root
spring.shardingsphere.datasource.ds2.password=
spring.shardingsphere.datasource.ds3.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds3.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds3.url=jdbc:mysql://localhost:3306/ds3?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=15000&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds3.username=root
spring.shardingsphere.datasource.ds3.password=
spring.shardingsphere.datasource.ds4.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds4.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds4.url=jdbc:mysql://localhost:3306/ds4?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=15000&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds4.username=root
spring.shardingsphere.datasource.ds4.password=
spring.shardingsphere.datasource.ds5.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds5.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds5.url=jdbc:mysql://localhost:3306/ds5?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=15000&allowMultiQueries=true&useSSL=false
spring.shardingsphere.datasource.ds5.username=root
spring.shardingsphere.datasource.ds5.password=
#### 分库策略 多库单表 ######
##### 数据节点 #####
##用户信息1sys_user
spring.shardingsphere.sharding.tables.sys_user.actual-data-nodes=ds$->{0..5}.sys_user
##用户地址2address
spring.shardingsphere.sharding.tables.address.actual-data-nodes=ds$->{0..5}.address
#分片场景
#1sys_user分片列名称
spring.shardingsphere.sharding.tables.sys_user.database-strategy.standard.sharding-column=sid
#分片算法,由于使用了uuid 的 sid使用groovy的表达式不能满足,需要自己实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.sys_user.database-strategy.standard.precise-algorithm-class-name=com.sharding.dbtablejpa.config.DataBasesPreciseShardingAlgorithm
#2addresses分片列名称
spring.shardingsphere.sharding.tables.address.database-strategy.standard.sharding-column=sid
#分片算法,由于使用了uuid 的 sid使用groovy的表达式不能满足,需要自己实现PreciseShardingAlgorithm接口并提供无参数的构造器
spring.shardingsphere.sharding.tables.address.database-strategy.standard.precise-algorithm-class-name=com.sharding.dbtablejpa.config.DataBasesPreciseShardingAlgorithm
4 uuid的分片字段sid 类的实现
public class DataBasesPreciseShardingAlgorithm implements PreciseShardingAlgorithm {
/**
*
* @param collection 库名集合
* @param preciseShardingValue 分片列
* @return
*/
@Override
public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
// 分片字段值
String value = preciseShardingValue.getValue();
return "ds"+TabSuffix.getTabSuffixCurrent(6,value);
}
}
public class TabSuffix {
/**
* 根据UUID首字母的ASC码获取表.
* UUID首字母包含[0123456789abcdefghijklmnopqrstuvwxyz]
* 分表个数必须被36整除或整除36(1 2 3 4 6 9 12 18 36)
* @return 结果如"1"
*/
public static String getTabSuffixCurrent(int splitdemision, String uuidStr){
System.out.println("uuidStr"+uuidStr);
System.out.println("splitdemision"+splitdemision);
// 无法被36整除,异常返回-1
if(36 % splitdemision != 0){
return "-1";
}
// 获取首字母asc值(第一种)
int asc = getAsc(uuidStr.substring(0,1));
// 获取字母的hashCode(第二种)
// int asc = uuidStr.substring(0,1).hashCode();
if(splitdemision == 1 || splitdemision == 2 || splitdemision == 3
|| splitdemision == 4 || splitdemision == 12){
if(asc == 121 || asc == 122){
asc += 9;
}
}else if(splitdemision == 9){
if(asc == 120){
asc += 3;
}
}else if(splitdemision == 18){
if(asc == 120 || asc == 121 || asc == 122){
asc -= 8;
}
}else if(splitdemision == 36){
if(asc == 120 || asc == 121 || asc == 122){
asc += 10;
}
}
int tableIdx = asc % splitdemision + 1;
return String.valueOf(tableIdx-1);
}
/**
* 字符转ASC
*
* @param st
* @return
*/
public static int getAsc(String st) {
byte[] gc = st.getBytes();
return (int) gc[0];
}
public static void main(String[] args) {
// 初始UUID首字母
String str ="2,8,b,b,8,2,1";
String[] strGro = str.split(",");
// 表下标:1 2 3 4 9 12 18 36
int splitdemision = 6;
TreeMap map = new TreeMap<>();
for (String item : strGro) {
item += "uuid";
int value = Integer.parseInt(getTabSuffixCurrent(splitdemision, item));
if(map.containsKey(value)){
map.put(value, map.get(value)+1);
}else{
map.put(value, 1);
}
}
// 测试打印数据
for (Entry entry : map.entrySet()) {
System.out.println(entry.getKey()+"--"+entry.getValue());
}
}
}
此算法引用自 https://blog.csdn.net/hanshimeng/article/details/88915573 谢谢。
5 测试类省略。自行编写user的增加和address地址的增加,看为uuid 的sid user 是否和address是否落在一个数据库。同样查询删除。
6 不需要分表的配置如下
### 不需要分表的 配置####
#bc配置表1config
spring.shardingsphere.sharding.tables.config_info.actual-data-nodes=ds0.config_info
##配置不分表默认数据源和表
spring.shardingsphere.sharding.default-data-source-name=ds0
spring.shardingsphere.sharding.binding-tables=config_info