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到了没

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐