微信技术群:Day9884125
1 complex复合分片算法
1.1 application.properties文件
# 配shardingsphere虚拟数据库,多库操作配置
spring.shardingsphere.datasource.names=database1, database2
# 配database1的数据源
spring.shardingsphere.datasource.database1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.database1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.database1.url=jdbc:mysql://8.142.93.199:3306/manage?useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.database1.username=root
spring.shardingsphere.datasource.database1.password=Duay4125!
# 配database2的数据源
spring.shardingsphere.datasource.database2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.database2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.database2.url=jdbc:mysql://123.56.5.188:3306/managecopy?useUnicode=true&characterEncoding=UTF-8
spring.shardingsphere.datasource.database2.username=root
spring.shardingsphere.datasource.database2.password=Lhl12345!
# 配置逻辑表student,actual-data-nodes代表真实表分布,代表database1和database2库里面的student1和student2表
# 前提数据库必须有student1和student2这两张表,他不会自己创建,否则会报错
spring.shardingsphere.sharding.tables.student.actual-data-nodes=database$->{1..2}.student_$->{1..2}
# 数据库中表的配置
# 数据库中表的student主键是id列
spring.shardingsphere.sharding.tables.student.key-generator.column=id
# 主键生成策略是雪花算法
spring.shardingsphere.sharding.tables.student.key-generator.type=SNOWFLAKE
# worker.id是雪花算法里面需要的参数,这个参数是可选的,我们建议配上
spring.shardingsphere.sharding.tables.student.key-generator.props.worker.id=1
# 按照多个字段查询的配置方式
spring.shardingsphere.sharding.tables.student.table-strategy.complex.sharding-columns=id,tearchid
# 这需要自己定义一个算法类,范围查询配置类
spring.shardingsphere.sharding.tables.student.table-strategy.complex.algorithm-class-name=com.example.sharding.shardingsphere.algorithm.OneComplexKeysShardingAlgorithm
# 数据库中库的配置
# 配分库分表的表策略,sharding-column是分片的键
spring.shardingsphere.sharding.tables.student.database-strategy.complex.sharding-columns=id,tearchid
# 范围查询的库配置
spring.shardingsphere.sharding.tables.student.database-strategy.complex.algorithm-class-name=com.example.sharding.shardingsphere.algorithm.OneDBComplexKeysShardingAlogorithm
# 打印实时日志
spring.shardingsphere.props.sql.show=true
1.2 实体类
package com.example.sharding.shardingsphere.entity;
import lombok.Data;
/**
* 作者: duay
* 时间:2022/06/09
* 描述:shardingjdbc实体类
*/
@Data
public class Student {
/** 主键id
* org.springframework.dao.DuplicateKeyException:
* Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException:
* Duplicate entry '0' for key 'PRIMARY'
*
* 当类型是 int和不是包装类long时,shardingjdbc的雪花算法不会起效,会报上面的错
* 主键id是Long,数据库的id可以是varchar类型
*/
private Long id;
/** 名字 */
private String name;
/** 老师id */
private int tearchid;
/** 状态 */
private String status;
}
1.3 mapper接口
package com.example.sharding.shardingsphere.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sharding.shardingsphere.entity.Student;
/**
* 作者: duay
* 时间:2022/06/09
* 描述:继承mybatisplus提供的BaseMapper,这样就不用写crud了
*/
public interface StudentMapper extends BaseMapper<Student> {
}
1.4 启动函数
package com.example.sharding.shardingsphere;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//用于扫描mapper接口类
@MapperScan("com.example.sharding.shardingsphere.mapper")
public class ShardingsphereApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingsphereApplication.class, args);
}
}
1.5 分片规则类
1.5.1 表分片规则
package com.example.sharding.shardingsphere.algorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* 作者:duay
* 时间:2022/06/09
* 描述:按照多个字段查询的算法
*/
public class OneComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
/**
* @param collection: 目标数据源或者表的值
* @param complexKeysShardingValue: logicTableName逻辑表名,
* columnNameAndShardingValuesMap分片列的精确值集合
* columnNameAndRangeValuesMap分片列的范围值集合
* @return
*/
@Override
public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
// 实现between进行范围分片
// 例如 select * from student where id in (1, 3, 5) and tearchid between 200 and 300;
Collection<Long> id = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("id");
Range<Long> range = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("tearchid");
List<String> result = new ArrayList<>();
Long lowerEndpoint = range.lowerEndpoint();//200
Long upperEndpoint = range.upperEndpoint();//300
//实现自定义分片逻辑 例如可以自己实现student_$->{id%2+1 + (30-20)+1}这样的分片逻辑
for(Long id2 : id){
BigInteger idResult = BigInteger.valueOf(id2);
BigInteger target = (idResult.mod(BigInteger.valueOf(2L))).add(new BigInteger("1"));
result.add("student_" + target);
}
return result;
}
}
1.5.2 库分片规则
package com.example.sharding.shardingsphere.algorithm;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 描述: 自定义分库规则类
* 作者: duay
* 时间: 2022/06/12
*/
public class OneDBComplexKeysShardingAlogorithm implements ComplexKeysShardingAlgorithm<Long> {
/**
* @param collection: 所有的数据源
* @param complexKeysShardingValue: sql执行时传入的分片值
* @return: 返回
*/
@Override
public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
Collection<Long> ids = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("id");
//Range<Long> ids = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("id");
List<String> result = new ArrayList<>();
for(Long id : ids){
BigInteger idResult = BigInteger.valueOf(id);
System.out.println("id{}" + id);
BigInteger index = (idResult.mod(BigInteger.valueOf(2L))).add(new BigInteger("1"));
System.out.println("目标数据库{}" + "database" + index);
result.add("database" + index);
}
return result;
}
}
1.6 测试类
package com.example.sharding.shardingsphere;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sharding.shardingsphere.entity.Student;
import com.example.sharding.shardingsphere.mapper.StudentMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
@SpringBootTest
@RunWith(SpringRunner.class)
public class ShardingTest {
@Resource
private StudentMapper studentMapper;
@Test
public void addStudent(){
for(int i=0; i<10; i++){
Student s = new Student();
//主键就不需要了,因为主键是雪花算法
//sdto.setId(1);
s.setName("张三");
s.setStatus("1");
s.setTearchid(10);
studentMapper.insert(s);
}
}
@Test
public void queryStudent(){
QueryWrapper result = new QueryWrapper<Student>();
// 精确查询
//result.eq("id", 1535492214268665858L);
result.in("id", 1535492214268665858L, 1535492218039345154L);
result.between("tearchid", 1L, 6L);
for(Object o : studentMapper.selectList(result)){
System.out.println("查询结果:" + o);
}
}
}
1.7 总结
1、首先测试类中只是用精确会报错,例如result.eq("id", 1535492214268665858L)。而使用result.in("id", 1535492214268665858L, 1535492218039345154L);和result.between("tearchid", 1L, 6L);可以正常使用。使用result.eq("id", 1535492214268665858L);和result.between("tearchid", 1L, 6L);也可以使用。
2、再者需要注意的是,complex分片算法的实现类需要继承的接口都是同一个叫做ComplexKeysShardingAlgorithm,而standard分片算法是两个,这里主要注意一下。
3、需要又特意注意,一般网上实现的都是complex算法的分表实现类。没有实现分库的。分库和分表的有一个区别。分库时候这个实现类需要注意以下几点。
/**
* 1、分库中获取的时候,注意complexKeysShardingValue参数中方法两个方法
* getColumnNameAndShardingValuesMap()是用来获取精确查询的列名
* getColumnNameAndRangeValuesMap()是用来获取范围查询的列名
* 这两个方法获取时候不能乱用,必须针对测试类中的列名使用。如果对这个列名使用的精确查询,在
* 算法中使用第一个方法获取。如果对列名值进行范围查询用第二个方法获取
*
* 2、用来作为落库的列名,在查询的时候,个人建议:落库列名不要使用范围查询。如果这个列名
* 使用范围查询,则getColumnNameAndShardingValuesMap()方法会报错找不到库
*/
Collection<Long> ids = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("id");
Range<Long> ids = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("id");