springboot整合sharding-jdbc简单操作
shardingjdbc,挺好的一个框架,现在改名叫shardingsphere了,话不多说,开始使用。<!-- sharding-jdbc --><dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter<
shardingjdbc,现在改名叫shardingsphere了,学习一下他的基本使用。官网地址:https://shardingsphere.apache.org/
我这里暂时用的是3.x版本的,这里暂时不提分库的事,所以在接下来的配置的时候会把相关的配置信息给删除掉
配置教程
添加依赖
<!-- sharding-jdbc -->
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>3.1.0</version>
</dependency>
首先贴上我们的主角-》表,
@Data
@Table(name="course")//逻辑表名称
public class Course {
@Id
private Long cid;
private String cname;
private Long userId;
private Integer cstatus;
}
数据库表信息
一、分表,按照status的值取模分表
# 打印输出SQL
spring.shardingsphere.props.sql.show=true
#提示要加
spring.main.allow-bean-definition-overriding=true
sharding.jdbc.datasource.names=ds0
sharding.jdbc.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.ds0.url=jdbc:mysql://127.0.0.1:3306/ljw?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true
sharding.jdbc.datasource.ds0.username=root
sharding.jdbc.datasource.ds0.password=123456
sharding.jdbc.config.sharding.tables.course.actual-data-nodes=ds0.course_$->{1..2}
sharding.jdbc.config.sharding.tables.course.table-strategy.inline.sharding-column=cstatus
sharding.jdbc.config.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cstatus % 2+1}
sharding.jdbc.config.sharding.tables.course.key-generator-column-name=cid
# 这个打印SQL效果更佳
sharding.jdbc.config.props.sql.show = true
代码测试如下:
@Autowired
CourseMapper courseMapper;
@GetMapping("/get")
public void getData(){
List<Course> list = courseMapper.selectAll();
System.err.println(list);
}
@GetMapping("/insertCourse")
public void insertCourse(){
for(int i=0;i<10;i++){
Course c = new Course();
c.setCname("课程名称"+i);
c.setCstatus(i);
c.setUserId(1L);
courseMapper.insertSelective(c);
}
}
}
然后插入数据测试,可以发现数据均匀的分部在两个表中
查询测试,两个表,每个表中各有五条,查询结果符合预期
二、读写分离,用sys_user表作为测试
@Data
@Table(name="sys_user")
public class SysUser {
@Id
private Integer id;
private String account;
private String email;
private String phone;
}
先看一下两个表的数据情况,主数据源如下
从数据源数据情况如下
配置
spring.main.allow-bean-definition-overriding=true
sharding.jdbc.datasource.names=master,slave0
sharding.jdbc.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.master.url=jdbc:mysql://127.0.0.1:3306/ljw?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true
sharding.jdbc.datasource.master.username=root
sharding.jdbc.datasource.master.password=123456
sharding.jdbc.datasource.slave0.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.slave0.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.slave0.url=jdbc:mysql://101.132.238.80:3306/ljw?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true
sharding.jdbc.datasource.slave0.username=root
sharding.jdbc.datasource.slave0.password=root
sharding.jdbc.config.masterslave.load-balance-algorithm-type=round_robin
sharding.jdbc.config.masterslave.name=ms
sharding.jdbc.config.masterslave.master-data-source-name=master
sharding.jdbc.config.masterslave.slave-data-source-names=slave0
sharding.jdbc.config.props.sql.show=true
测试代码
@Autowired
SysUserMapper sysUserMapper;
@GetMapping("/insertData")
public void insert(){
System.err.println("******************************");
SysUser user = new SysUser();
user.setAccount(UUID.randomUUID().toString());
user.setEmail("12323");
user.setPhone("150***");
sysUserMapper.insertSelective(user);
}
@GetMapping("/getData")
public void getData(){
List<SysUser> list = sysUserMapper.selectAll();
System.err.println(list);
}
插入数据的信息确实在主数据源中,从数据源没有数据
读取数据测试效果如下,走的从库
三、读写分离+数据分表,表还用刚才的course测试
# 打印输出SQL
spring.shardingsphere.props.sql.show=true
spring.main.allow-bean-definition-overriding=true
sharding.jdbc.datasource.names=master,slave
sharding.jdbc.datasource.master.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.master.url=jdbc:mysql://127.0.0.1:3306/ljw?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true
sharding.jdbc.datasource.master.username=root
sharding.jdbc.datasource.master.password=123456
sharding.jdbc.datasource.slave.type=com.alibaba.druid.pool.DruidDataSource
sharding.jdbc.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
sharding.jdbc.datasource.slave.url=jdbc:mysql://101.132.238.80:3306/ljw?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&allowMultiQueries=true
sharding.jdbc.datasource.slave.username=root
sharding.jdbc.datasource.slave.password=root
sharding.jdbc.config.sharding.tables.course.actual-data-nodes=ds0.course_$->{1..2}
sharding.jdbc.config.sharding.tables.course.table-strategy.inline.sharding-column=cstatus
sharding.jdbc.config.sharding.tables.course.table-strategy.inline.algorithm-expression=course_$->{cstatus % 2+1}
sharding.jdbc.config.sharding.tables.course.key-generator-column-name=cid
#sharding.jdbc.config.sharding.binding-tables=course
#sharding.jdbc.config.sharding.broadcast-tables=t_config
sharding.jdbc.config.sharding.master-slave-rules.ds0.master-data-source-name=master
sharding.jdbc.config.sharding.master-slave-rules.ds0.slave-data-source-names=slave
这个代码可以自己测试,我就不贴测试结果了,有兴趣的可以自己试试
回头有空试试再去了解一下新版本的代码配置。
2022-4-15 范围分表
上面的分表是进行取模分表,扩展不好扩展,接下来我们使用范围分表。这里我们使用id进行范围分
先建立好表
//这俩依赖保持一致
<!-- sharding-jdbc -->
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>io.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<version>3.1.0</version>
</dependency>
配置
# 数据源 ds0
sharding:
jdbc:
datasource:
names: ds0
# 第一个数据库
ds0:
type: com.zaxxer.hikari.HikariDataSource # com.alibaba.druid.pool.DruidDataSource 使用这个会报错,不知道为啥
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/ljw?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: root
password: root
# 水平拆分的数据库(表) 配置分库 + 分表策略 行表达式分片策略
config:
sharding:
tables:
book: ##虚拟表名称
actual-data-nodes: ds0.book_$->{1..2} # 实际表
table-strategy:
standard:
precise-algorithm-class-name: com.ljw.lovely.config.MayiktRangeShardingAlgorithm
sharding-column: id
# 打印执行的数据库
props:
sql:
show: true
# 打印执行的sql语句
spring:
main:
allow-bean-definition-overriding: true
分表配置类
import io.shardingsphere.api.algorithm.sharding.PreciseShardingValue;
import io.shardingsphere.api.algorithm.sharding.standard.PreciseShardingAlgorithm;
import lombok.extern.slf4j.Slf4j;
import java.util.Collection;
@Slf4j
public class MayiktRangeShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
private Long TABLE_SIZE = 5l;//假设每张表最多存放五条数据
private String TABLE_NAME = "book_";
@Override
public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
Double temp = Double.valueOf(preciseShardingValue.getValue()) / TABLE_SIZE;//根据id计算每条数据存放的表
String tableName = TABLE_NAME + (int) Math.ceil(temp);
log.info("<tableName{}>", tableName);
return tableName;
}
}
测试使用。这里弄个for循环模拟十条数据
@GetMapping("/save")
public String sendMsg1(HttpServletRequest request) throws InterruptedException {
for (int i=1;i<10;i++){
BookEntity bookEntity = new BookEntity(i,"小明"+i,i+10,"150****081"+i);
bookMapper.insert(bookEntity);
}
return "访问成功1";
}
效果
存在的问题?
按照这样分表的话会存在一个问题,为了减少每张表的数据量我们才进行分表的,我们查询某条数据的时候,如果我们根据分表的字段(id)进行查询,那么他可以定位到某张表中,但是实际场景下我们会根据phone查询的概率也很大,此时就相当于全表扫描了,他会查询所有表,去定位到某条数据,我们可以看一下SQL打印。
使用id查询:
@GetMapping("/list")
public List<BookEntity> getList() {
QueryWrapper<BookEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id",3);
return bookMapper.selectList(queryWrapper);
}
使用phone查询
@GetMapping("/list")
public List<BookEntity> getList() {
QueryWrapper<BookEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("phone","150****0816");
return bookMapper.selectList(queryWrapper);
}
这里很明显出现了这种问题,那么在实际场景下查询效率会很低,那么我们如何解决呢。通过映射表来处理。
我们先创建一个表book_id,设置表id自增。其中phone用来存放book表中的phone。这样做有两个好处
好处1:使用book_id表的id进行分表,可以保证book表的id自增且有序
好处2:通过存储了phone字段,可以直接定位到id,从而直接找到具体表
实战效果开始。
中间表
@TableName("book_id")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookId implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String phone;
}
修改保存方法
@GetMapping("/save")
public String sendMsg1(HttpServletRequest request) throws InterruptedException {
for (int i=1;i<10;i++){
//BookEntity bookEntity = new BookEntity(i,"小明"+i,i+10,"150****081"+i);
BookEntity bookEntity = new BookEntity();
bookEntity.setName("小明"+i);
bookEntity.setPrice(i+10);
bookEntity.setPhone("150****081"+i);
BookId bookId = new BookId();
bookId.setPhone(bookEntity.getPhone());
bookIdMapper.insert(bookId);
bookEntity.setId(bookId.getId());
bookMapper.insert(bookEntity);
}
return "访问成功1";
}
数据库数据分布
改造一下我们的查询方法,此时我们再根据phone查询,直接就定位到了book_2表进行查询
@GetMapping("/list")
public List<BookEntity> getList() {
String phone="150****0816";
//先根据映射表找到id
QueryWrapper<BookId> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("phone",phone);
BookId bookId = bookIdMapper.selectOne(queryWrapper);
//查询的时候将id字段条件补充上去
QueryWrapper<BookEntity> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("phone",phone);
queryWrapper1.eq("id",bookId.getId());
return bookMapper.selectList(queryWrapper1);
}
以上就是对一个表进行分表存放、查询进行实战的一个处理。get到了没
更多推荐
所有评论(0)