使用spring boot集成shardingsphere分库分表简易测试

news2024/11/13 8:04:21

根据如下pom整上一个spring-boot项目,spring-boot版本用2.3.5,shardingsphere用5.1.1。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.shardingsphere</groupId>
    <artifactId>shardingsphere-test</artifactId>
    <version>1.0-SNAPSHOT</version>


    <!--引入spring boot 2.3.5 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.5.RELEASE</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!--spring boot的web模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入shardingsphere-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>5.1.1</version>
        </dependency>

        <!--引入mybatis plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>
        <!--引入mysal connector-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--引入Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--引入spring 测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

        <!--spring 测试类-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

再用mysql整一个名为shardingsphere-test的库(编码集utf8mb4,也可以选自己喜欢的编码集),再往里弄上两个测试表。

CREATE TABLE t_course_1 (
  `cid` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) DEFAULT NULL,
  `cname` VARCHAR(50) DEFAULT NULL,
  `brief` VARCHAR(50) DEFAULT NULL,
  `price` DOUBLE DEFAULT NULL,
  `status` INT(11) DEFAULT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;


CREATE TABLE t_course_2 (
  `cid` BIGINT(20) NOT NULL,
  `user_id` BIGINT(20) DEFAULT NULL,
  `cname` VARCHAR(50) DEFAULT NULL,
  `brief` VARCHAR(50) DEFAULT NULL,
  `price` DOUBLE DEFAULT NULL,
  `status` INT(11) DEFAULT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

项目结构如下。

application.yml的配置及解释如下:

spring:
  application:
    name: sharding-jdbc-demo # 应用名称
  shardingsphere:
    # 设置全局属性
    props:
      # 打开SQL显示功能,将会打印出执行的原始SQL和实际路由后的SQL
      sql-show: true
    # 数据源配置
    datasource:
      # 定义数据源名称列表,这里只有一个名为db1的数据源
      names: db1
      # 数据源db1的具体配置
      db1:
        # 数据源实现类,此处使用HikariCP连接池
        type: com.zaxxer.hikari.HikariDataSource
        # JDBC驱动类名,对应MySQL数据库驱动
        driver-class-name: com.mysql.jdbc.Driver
        # 数据库连接URL,连接本地MySQL服务器上的shardingsphere-test数据库,并设置字符编码和禁用SSL
        url: jdbc:mysql://127.0.0.1:3306/shardingsphere-test?characterEncoding=UTF-8&useSSL=false
        # 数据库用户名
        username: root
        # 数据库密码
        password: root

    # 规则配置部分
    rules:
      # 分片规则相关配置
      sharding:
        # 1.定义分片表的实际分布情况
        tables:
          # 针对表t_course的分片配置
          t_course:
            # 实际数据节点分布,表明t_course表被分成两张表,分别命名为t_course_0和t_course_1,并存储在db1数据库中
            actual-data-nodes: "db1.t_course_$->{1..2}"
            # 配置策略
            table-strategy:
              # 用于单分片键的标准分片场景
              standard:
                sharding-column: cid
                # 分片算法名字
                sharding-algorithm-name: course_inline
            # 分布式主键生成策略配置
            key-generate-strategy:
              # 主键列名为cid
              column: cid
              # 引用已定义的分布式序列生成器  alg-snowflake
              key-generator-name: snowflake

        # 2.定义分布式序列生成器
        key-generators:
          # 定义名为alg-snowflake的分布式序列生成器  alg-snowflake
          snowflake:
            # 类型为SNOWFLAKE算法,用于生成全局唯一ID
            type: SNOWFLAKE

        # 3.定义分片算法
        sharding-algorithms:
          # 定义名为table-inline的分片算法
          course_inline:
            # 使用INLINE类型的行表达式分片算法
            type: INLINE
            # 算法属性配置
            props:
              # 行表达式算法具体内容,按照cid模2加1的值来确定数据落入哪张表,例如:cid%2+1=0,则落入t_course_1,等于1则落入t_course_2
              algorithm-expression: t_course_$->{cid % 2 + 1}

        # 4.定义分片策略
        #sharding-strategies:
          # 对于表t_course的分片策略定义
          #t_course_strategy:
            # 使用标准分片策略
            #type: STANDARD
            # 指定分片键为cid列
            #sharding-column: cid
            # 引用已定义的分片算法
            #sharding-algorithm-name: course_inline


# SQL输出日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

再弄一个对应数据库的实体类。

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;

@TableName("t_course")
@Data
@ToString
public class Course {

    //@TableId(type = IdType.AUTO)
    @TableId
    private Long cid;

    private Long userId;

    private Long corderNo;

    private String cname;

    private String brief;

    private Double price;

    private Integer status;

}

再搞一个mapper。

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.shardingsphere.demo.entity.Course;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface CourseMapper extends BaseMapper<Course> {

}

再搞一个service接口。

public interface CoureInterface {

    public void addCoure();
}

按道上的规矩再搞一个service接口的实现类。

import com.shardingsphere.demo.coure.CoureInterface;
import com.shardingsphere.demo.entity.Course;
import com.shardingsphere.demo.mapper.CourseMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CoureInterfaceImpl implements CoureInterface {

    @Autowired
    private CourseMapper courseMapper;

    @Override
    public void addCoure() {
        for (int i = 0; i < 30; i++) {
            Course course = new Course();
            // 注意: cid使用雪花算法配置了(还可以使用MybatisPlus UUID),此处不用配置
            course.setUserId(1000L + i);
            course.setCname("ShardingSphere");
            course.setBrief("ShardingSphere测试");
            course.setPrice(66.6);
            course.setStatus(1);
            courseMapper.insert(course);
        }
    }
}

再弄上一个controller,来接收远方的呼唤。

import com.shardingsphere.demo.coure.CoureInterface;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CourseController {

    @Autowired
    private CoureInterface coureInterface;

    @RequestMapping(path = "/demo/addCourse")
    public void addCourse(){
        coureInterface.addCoure();
    }
}

最后再弄上一个spring boot的启动类,用来启动这个sping boot项目。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ShardingSphereTest {
    public static void main(String[] args) {
        SpringApplication.run(ShardingSphereTest.class, args);
    }
}

我们启动服务后,直接浏览器访问这个接口简单测试一下。

localhost:8080/demo/addCourse

再去数据库看一眼,发现如我们所想,数据已经被拆分到两个表中了。

趁热打铁,我们再进阶一小点,把库也给分了算了。

再找一台机器创建一个跟上面一模一样的数据库(shardingsphere-test),库里的表也跟上面建的一模一样两张表(t_course_1,t_course_2),这样我们就富裕了,有了俩数据库。

需要改造的地方就是我们的application.yml配置文件,加上分库操作。

spring:
  application:
    name: sharding-jdbc-demo-database # 应用名称
  shardingsphere:
    # 设置全局属性
    props:
      # 打开SQL显示功能,将会打印出执行的原始SQL和实际路由后的SQL
      sql-show: true
    # 数据源配置
    datasource:
      # 定义数据源名称列表,这里有两个数据源(数据的名字可以一样,也可以不一样)
      names: db1, db2
      # 数据源db1的具体配置
      db1:
        # 数据源实现类,此处使用HikariCP连接池
        type: com.zaxxer.hikari.HikariDataSource
        # JDBC驱动类名,对应MySQL数据库驱动
        driver-class-name: com.mysql.jdbc.Driver
        # 数据库连接URL,连接本地MySQL服务器上的shardingsphere-test数据库,并设置字符编码和禁用SSL
        url: jdbc:mysql://127.0.0.1:3306/shardingsphere-test?characterEncoding=UTF-8&useSSL=false
        # 数据库用户名
        username: root
        # 数据库密码
        password: root
      # 数据源db1的具体配置
      db2:
        # 数据源实现类,此处使用HikariCP连接池
        type: com.zaxxer.hikari.HikariDataSource
        # JDBC驱动类名,对应MySQL数据库驱动
        driver-class-name: com.mysql.jdbc.Driver
        # 数据库连接URL,连接本地MySQL服务器上的shardingsphere-test数据库,并设置字符编码和禁用SSL
        url: jdbc:mysql://124.223.XXX.XXX:3306/shardingsphere-test?characterEncoding=UTF-8&useSSL=false
        # 数据库用户名
        username: root
        # 数据库密码
        password: root

    # 规则配置部分
    rules:
      # 分片规则相关配置
      sharding:
        # 1.定义分片表的实际分布情况
        tables:
          # 针对表t_course的分片配置
          t_course:
            # 实际数据节点分布,表明t_course表被分成两张表,分别命名为t_course_0和t_course_1,并存储在db1数据库中
            actual-data-nodes: "db$->{1..2}.t_course_$->{1..2}"
            # 配置库策略
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: table_inline

            # 配置表策略
            table-strategy:
              # 用于单分片键的标准分片场景
              standard:
                sharding-column: cid
                # 分片算法名字
                sharding-algorithm-name: course_inline
            # 分布式主键生成策略配置
            key-generate-strategy:
              # 主键列名为cid
              column: cid
              # 引用已定义的分布式序列生成器  alg-snowflake
              key-generator-name: snowflake

        # 2.定义分布式序列生成器
        key-generators:
          # 定义名为alg-snowflake的分布式序列生成器  alg-snowflake
          snowflake:
            # 类型为SNOWFLAKE算法,用于生成全局唯一ID
            type: SNOWFLAKE

        # 3.定义分片算法
        sharding-algorithms:
          #定义库分片算法
          table_inline:
            type: INLINE
            props:
              algorithm-expression: db$->{user_id % 2 + 1}
          # 定义名为table-inline的分片算法,表分片
          course_inline:
            # 使用INLINE类型的行表达式分片算法
            type: INLINE
            # 算法属性配置
            props:
              # 行表达式算法具体内容,按照cid模2加1的值来确定数据落入哪张表,例如:cid%2+1=0,则落入t_course_1,等于1则落入t_course_2
              algorithm-expression: t_course_$->{cid % 2 + 1}

        # 4.定义分片策略
        #sharding-strategies:
          # 对于表t_course的分片策略定义
          #t_course_strategy:
            # 使用标准分片策略
            #type: STANDARD
            # 指定分片键为cid列
            #sharding-column: cid
            # 引用已定义的分片算法
            #sharding-algorithm-name: course_inline


# SQL输出日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

然后重启服务,重新访问localhost:8080/demo/addCourse 调用添加数据的服务接口,此时再查数据库就会发现数据已经被shardingsphere分到不同库的不同表里了。

分库查询

        入库了以后,我们写个测试类尝试查询一下,看看会是怎么样。

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class MyTest {
    @Autowired(required = false)
    private CourseMapper courseMapper;

     /**
     * 水平分片:查询所有记录
     * 查询了两个数据源,每个数据源中使用UNION ALL连接两个表
     */
    @Test
    public void testShardingSelectOne(){
        List<Course> courses = courseMapper.selectList(null);
        courses.forEach(System.out::println);
    }

}

我们来看一下查询结果。

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@30b0d5a7] was not registered for synchronization because synchronization is not active
JDBC Connection [org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection@411e567e] will not be managed by Spring
==>  Preparing: SELECT cid,user_id,cname,brief,price,status FROM t_course 
==> Parameters: 
2024-04-19 21:17:29.909  INFO 25740 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT  cid,user_id,cname,brief,price,status  FROM t_course
2024-04-19 21:17:29.909  INFO 25740 --- [           main] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2024-04-19 21:17:29.910  INFO 25740 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT  cid,user_id,cname,brief,price,status  FROM t_course_1 UNION ALL SELECT  cid,user_id,cname,brief,price,status  FROM t_course_2
2024-04-19 21:17:29.910  INFO 25740 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT  cid,user_id,cname,brief,price,status  FROM t_course_1 UNION ALL SELECT  cid,user_id,cname,brief,price,status  FROM t_course_2
<==    Columns: cid, user_id, cname, brief, price, status
<==        Row: 1781311094111928321, 1000, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311097660309505, 1002, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311098117488641, 1004, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311098650165249, 1006, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311097660309506, 1003, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311098184597506, 1005, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311098650165250, 1007, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==        Row: 1781311096750145537, 1001, ShardingSphere, ShardingSphere尝试查询, 99.0, 1
<==      Total: 8

可以看到,它是把每个库的每张表进行union操作,返回返回总结果。

多表关联查询

        如果我们要是多表查询呢?先建上两张有关联的表来试一下。如下两个数据库分别创建t_order0,t_order1,t_order_item0,t_order_item1,仍然分库分表创建,只不过让t_order和t_order_item有联系,即有如此关联:SELECT o.*,i.* FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no;

CREATE TABLE t_order0 (
  id BIGINT,
  order_no VARCHAR(30),
  user_id BIGINT,
  amount DECIMAL(10,2),
  PRIMARY KEY(id) 
);
CREATE TABLE t_order1 (
  id BIGINT,
  order_no VARCHAR(30),
  user_id BIGINT,
  amount DECIMAL(10,2),
  PRIMARY KEY(id) 
);


CREATE TABLE t_order_item0(
    id BIGINT,
    order_no VARCHAR(30),
    user_id BIGINT,
    price DECIMAL(10,2),
    `count` INT,
    PRIMARY KEY(id)
);

CREATE TABLE t_order_item1(
    id BIGINT,
    order_no VARCHAR(30),
    user_id BIGINT,
    price DECIMAL(10,2),
    `count` INT,
    PRIMARY KEY(id)
);

再在配置文件中将这俩表的配置搞好。

spring:
  application:
    name: sharding-jdbc-demo-database # 应用名称
  shardingsphere:
    # 设置全局属性
    props:
      # 打开SQL显示功能,将会打印出执行的原始SQL和实际路由后的SQL
      sql-show: true
    # 数据源配置
    datasource:
      # 定义数据源名称列表,这里有两个数据源(数据的名字可以一样,也可以不一样)
      names: db1, db2
      # 数据源db1的具体配置
      db1:
        # 数据源实现类,此处使用HikariCP连接池
        type: com.zaxxer.hikari.HikariDataSource
        # JDBC驱动类名,对应MySQL数据库驱动
        driver-class-name: com.mysql.jdbc.Driver
        # 数据库连接URL,连接本地MySQL服务器上的shardingsphere-test数据库,并设置字符编码和禁用SSL
        url: jdbc:mysql://127.0.0.1:3306/shardingsphere-test?characterEncoding=UTF-8&useSSL=false
        # 数据库用户名
        username: root
        # 数据库密码
        password: root
      # 数据源db1的具体配置
      db2:
        # 数据源实现类,此处使用HikariCP连接池
        type: com.zaxxer.hikari.HikariDataSource
        # JDBC驱动类名,对应MySQL数据库驱动
        driver-class-name: com.mysql.jdbc.Driver
        # 数据库连接URL,连接本地MySQL服务器上的shardingsphere-test数据库,并设置字符编码和禁用SSL
        url: jdbc:mysql://124.223.XXX.XXX:3306/shardingsphere-test?characterEncoding=UTF-8&useSSL=false
        # 数据库用户名
        username: root
        # 数据库密码
        password: 123456

    # 规则配置部分
    rules:
      # 分片规则相关配置
      sharding:
        # 1.定义分片表的实际分布情况
        tables:
          # 针对表t_course的分片配置
          t_course:
            # 实际数据节点分布,表明t_course表被分成两张表,分别命名为t_course_0和t_course_1,并存储在db1数据库中
            actual-data-nodes: "db$->{1..2}.t_course_$->{1..2}"
            # 配置库策略
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: table_inline

            # 配置表策略
            table-strategy:
              # 用于单分片键的标准分片场景
              standard:
                sharding-column: cid
                # 分片算法名字
                sharding-algorithm-name: course_inline
            # 分布式主键生成策略配置
            key-generate-strategy:
              # 主键列名为cid
              column: cid
              # 引用已定义的分布式序列生成器  alg-snowflake
              key-generator-name: snowflake

          #order表的分片分库策略
          t_order:
            # 实际数据节点分布,表明t_course表被分成两张表,分别命名为t_course_0和t_course_1,并存储在db1数据库中
            actual-data-nodes: "db$->{1..2}.t_order$->{0..1}"
            # 配置分库策略
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: order_inline

            # 配置分表策略
            table-strategy:
              # 用于单分片键的标准分片场景,根据order_no的hash值进行分片
              standard:
                sharding-column: order_no
                # 分片算法名字
                sharding-algorithm-name: order_no_mod
            # 分布式主键生成策略配置
            key-generate-strategy:
              # 主键列名为cid
              column: id
              # 引用已定义的分布式序列生成器  alg-snowflake
              key-generator-name: snowflake

          #order表的分片分库策略
          t_order_item:
            # 实际数据节点分布,表明t_course表被分成两张表,分别命名为t_course_0和t_course_1,并存储在db1数据库中
            actual-data-nodes: "db$->{1..2}.t_order_item$->{0..1}"
            # 配置分库策略
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: order_inline

            # 配置分表策略
            table-strategy:
              # 用于单分片键的标准分片场景,根据order_no的hash值进行分片
              standard:
                sharding-column: order_no
                # 分片算法名字
                sharding-algorithm-name: order_no_mod
            # 分布式主键生成策略配置
            key-generate-strategy:
              # 主键列名为cid
              column: id
              # 引用已定义的分布式序列生成器  alg-snowflake
              key-generator-name: snowflake

        # 2.定义分布式序列生成器
        key-generators:
          # 定义名为alg-snowflake的分布式序列生成器  alg-snowflake
          snowflake:
            # 类型为SNOWFLAKE算法,用于生成全局唯一ID
            type: SNOWFLAKE

        # 3.定义你想配置表的分片算法
        sharding-algorithms:
          #定义库分片算法
          table_inline:
            type: INLINE
            props:
              algorithm-expression: db$->{user_id % 2 + 1}
          # 定义名为table-inline的分片算法,表分片
          course_inline:
            # 使用INLINE类型的行表达式分片算法
            type: INLINE
            # 算法属性配置
            props:
              # 行表达式算法具体内容,按照cid模2加1的值来确定数据落入哪张表,例如:cid%2+1=0,则落入t_course_1,等于1则落入t_course_2
              algorithm-expression: t_course_$->{cid % 2 + 1}

          order_inline:
            type: INLINE
            props:
              algorithm-expression: db$->{user_id % 2 + 1}
          order_no_mod:
            # 使用HASH_MOD类型的行表达式分片算法
            type: HASH_MOD
            # 算法属性配置
            props:
              # 行表达式算法具体内容,
              sharding-count: 2

        # 4.定义分片策略
        #sharding-strategies:
          # 对于表t_course的分片策略定义
          #t_course_strategy:
            # 使用标准分片策略
            #type: STANDARD
            # 指定分片键为cid列
            #sharding-column: cid
            # 引用已定义的分片算法
            #sharding-algorithm-name: course_inline


# SQL输出日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

OrderMapper改造一下,进行表关联。 

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.shardingsphere.demo.entity.Order;
import com.shardingsphere.demo.vo.OrderVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface OrderMapper extends BaseMapper<Order> {

    @Select({"SELECT o.order_no, SUM(i.price * i.count) AS amount",
            "FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no",
            "GROUP BY o.order_no"})
    List<OrderVo> getOrderAmount();
}

再写个测试方法。

    /**
     * 测试关联表查询
     */
    @Test
    public void testGetOrderAmount(){

        List<OrderVo> orderAmountList = orderMapper.getOrderAmount();
        orderAmountList.forEach(System.out::println);
    }

看看执行结果:

==>  Preparing: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no GROUP BY o.order_no 
==> Parameters: 
2024-04-19 21:27:52.938  INFO 21784 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no GROUP BY o.order_no
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:27:52.939  INFO 21784 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
<==    Columns: order_no, amount
<==        Row: ShardingSphere1, 40.00
<==        Row: ShardingSphere2, 40.00
<==        Row: ShardingSphere5, 6.00
<==        Row: ShardingSphere6, 6.00
<==      Total: 4

        发现了一个问题:可以看到同一个数据源中,查询的次数是t_ordert_order_item的笛卡尔积数量,但是t_order0中的订单数据只会在对应数据源中t_order_item0,不会在t_order_item1中,所以有些关联查询是没有意义的,那么接下来就引入了绑定表的概念。

绑定表

        指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。所以我们来配置一下,将t_ordert_order_item绑定一下,只需要在rules这里增加如下配置,如果你的配置文件是.properties类型的,需要这样配:spring.shardingsphere.rules.sharding.binding-tables[0]=t_order,t_order_item

# 规则配置部分
    rules:
      # 分片规则相关配置
      sharding:
        #绑定表
        binding-tables:
          - t_order,t_order_item

再次查询:

==>  Preparing: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no GROUP BY o.order_no 
==> Parameters: 
2024-04-19 21:43:08.069  INFO 24608 --- [           main] ShardingSphere-SQL                       : Logic SQL: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order o JOIN t_order_item i ON o.order_no = i.order_no GROUP BY o.order_no
2024-04-19 21:43:08.069  INFO 24608 --- [           main] ShardingSphere-SQL                       : SQLStatement: MySQLSelectStatement(table=Optional.empty, limit=Optional.empty, lock=Optional.empty, window=Optional.empty)
2024-04-19 21:43:08.070  INFO 24608 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:43:08.070  INFO 24608 --- [           main] ShardingSphere-SQL                       : Actual SQL: db1 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:43:08.070  INFO 24608 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order0 o JOIN t_order_item0 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
2024-04-19 21:43:08.070  INFO 24608 --- [           main] ShardingSphere-SQL                       : Actual SQL: db2 ::: SELECT o.order_no, SUM(i.price * i.count) AS amount FROM t_order1 o JOIN t_order_item1 i ON o.order_no = i.order_no GROUP BY o.order_no ORDER BY o.order_no ASC 
<==    Columns: order_no, amount
<==        Row: ShardingSphere1, 40.00
<==        Row: ShardingSphere2, 40.00
<==        Row: ShardingSphere5, 6.00
<==        Row: ShardingSphere6, 6.00
<==      Total: 4

突然一家伙少了四条查询。

  • 如果不配置绑定表:测试的结果为8个SQL。 多表关联查询会出现笛卡尔积关联。
  • 如果配置绑定表:测试的结果为4个SQL。 多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1613230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【KingSCADA】通过地址引用和弹窗模板实现设备控制

当相同的设备过多时&#xff0c;要做很多相同的弹窗&#xff0c;这种情况下可以通过地址引用和弹窗模板实现设备控制。 1.变量创建 2.画面开发 以阀门控制为例&#xff0c;只需要做一个阀门控制界面模板 3.地址引用 # 4.实现效果

Linux基本命令之正则表达式(转义字符)

一&#xff1a;查看二进制文件 strings 命令&#xff1a;strings 文件名 生成链接文件 ln 命令&#xff1a;ln 选项 源文件(f1) 链接文件&#xff08;f2&#xff09; 软连接&#xff1a;eg:ln -s f1 f2 软链接不能跨分区链接&#xff0c;但可以在同一分区的不同目录下链接…

小型架构实验模拟

一 实验需求 二 实验环境 22 机器&#xff1a; 做nginx 反向代理 做静态资源服务器 装 nginx keepalived filebeat 44机器&#xff1a; 做22 机器的备胎 装nginx keepalived 99机器&#xff1a;做mysql的主 装mysqld 装node 装filebeat 77机器&#xff1a;做mysq…

目标检测网络YOLO进化之旅

yolo系列网络在目标检测领域取得了巨大的成功&#xff0c; 尤其是在工程实践中&#xff0c; 以其出色的性能优势获得了广泛的应用落地。 YOLO的前3个版本是由同一个作者团队出品&#xff0c; 算是官方版本。 之后的版本都是各个研究团队自己改进的版本&#xff0c; 之间并无明…

Linux 安装 Docker +Docker Compose + cucker/get_command_4_run_container

TIP&#xff1a;下面演示的 Linux 系统为 CentOS 7.9。 Docker 更新你的系统并安装必要的依赖项&#xff1a; sudo yum update -y sudo yum install -y yum-utils device-mapper-persistent-data lvm2添加 Docker 的官方仓库&#xff1a; sudo yum-config-manager --add-rep…

ConcurrentHashMap 源码分析(一)

一、简述 本文对 ConcurrentHashMap#put() 源码进行分析。 二、源码概览 public V put(K key, V value) {return putVal(key, value, false); }上面是 ConcurrentHashMap#put() 的源码&#xff0c;我们可以看出其核心逻辑在 putVal() 方法中。 final V putVal(K key, V val…

golang本地缓存库之bigcache

1. 前言 上周工作之余逛github看到一个本地缓存库bigcache&#xff0c;这个是allegro公司开源的一个项目&#xff0c;主要是用于本地缓存使用&#xff0c;根据他们的博客说明&#xff0c;他们编写这个库最初的目的就是实现一个非常快速的缓存服务。 看了下bigcache这个库的源…

前端入门:HTML(CSS边框综合案例)

案例&#xff1a; 源代码&#xff1a; css-borders.html: <body> <div id"square"> </div> <br> <div id"triangle"> </div> <br> <div id"trapezium"> </div> <br> <div id…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第六套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第六套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadidadidida313&#xff0c;加我备注&#x…

Linux--Linux常用命令

Linux常用命令 前言Linux命令格式命令讲解1、ls:查看当前目录下所有的内容语法:ls[-al][dir]2、pwd: 查看当前所在目录3、cd : 切换目录4、touch[文件名] : 如果文件不存在新建文件5、mkdir: 创建目录6、rm: 删除指定文件7、rmdir: 删除空目录8、cat:用于显示文件内容9、m…

磁盘损坏无法读取:原因、恢复方案与防范之道

在数字化信息爆炸的时代&#xff0c;磁盘作为数据存储的重要载体&#xff0c;承载着无数重要的文件和资料。然而&#xff0c;当磁盘突然损坏&#xff0c;无法读取数据时&#xff0c;我们往往会陷入困境&#xff0c;焦虑不已。面对这种情况&#xff0c;我们该如何应对&#xff1…

python爬虫--------requests案列(二十七天)

兄弟姐们&#xff0c;大家好哇&#xff01;我是喔的嘛呀。今天我们一起来学习requests案列。 一、requests____cookie登录古诗文网 1、首先想要模拟登录&#xff0c;就必须要获取登录表单数据 登录完之后点f12&#xff0c;然后点击network&#xff0c;最上面那个就是登录接口…

ubuntu扩展根目录磁盘空间

ubuntu扩展根目录磁盘空间 扩展虚拟机磁盘空间 查看现有磁盘状态 查询现有分区状态&#xff0c;/dev/sda是我们要扩展的磁盘 fdisk -l 开始进行磁盘空间的扩容 parted /dev/sda#扩展3号分区的空间 resizepart 3刷新分区空间 resize2fs /dev/sda3查询扩展结果&#xff0c;…

BADI-AC_DOCUMENT-交货单过账科目替代

BADI-AC_DOCUMENT-交货单过账科目替代 一、业务场景 事务代码VL02N/VL22N及其他交货单过账事务&#xff0c;在交货单过账生成会计凭证的时候对科目进行替代 二、BADI增强&#xff1a;AC_DOCUMENT 这个BADI理论上可以处理很多的会计凭证科目替代&#xff0c;不止是交货单过账…

Redis入门到通关之数据结构解析-动态字符串SDS

文章目录 Redis数据结构-动态字符串动态扩容举例二进制安全SDS优点与C语言中的字符串的区别 Redis数据结构-动态字符串 我们都知道 Redis 中保存的Key是字符串&#xff0c;value 往往是字符串或者字符串的集合。可见字符串是 Redis 中最常用的一种数据结构。 不过 Redis 没有…

Django中间件的源码解析流程(上)——中间件载入的前置

目录 1. ​前言​ 2. 请求的入口 3. 中间件加载的入口 4. 源码中的闭包实现 5. 最后 1. 前言 哈喽&#xff0c;大家好&#xff0c;我是小K,今天咋们分享的内容是&#xff1a;在学会Django中间件之后&#xff0c; 我们继续深入底层源码。 在执行中间件时请求到来总是从前往后…

Golang那些违背直觉的编程陷阱

目录 知识点1&#xff1a;切片拷贝之后都是同一个元素 知识点2&#xff1a;方法集合决定接口实现&#xff0c;类型方法集合是接口方法集合的超集则认定为实现接口&#xff0c;否则未实现接口 切片拷贝之后都是同一个元素 package mainimport ("encoding/json"&quo…

[Kubernetes] etcd的集群基石作用

文章目录 1. 配置存储2. 数据一致性3. 服务发现与协调4. 集群状态中枢5. 集群稳定性 1. 配置存储 etcd作为一个高度可靠的分布式键值存储系统&#xff0c;存储了Kubernetes集群的完整配置和状态数据。集群的元数据&#xff0c;包括节点信息、命名空间、部署、副本集、服务、持…

【leetcode面试经典150题】65. 旋转链表(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

Mac电池管理软件 Batteries for Mac v2.2.9直装版

Batteries for Mac&#xff0c;作为一款专为Mac用户设计的电池管理软件&#xff0c;以其强大的功能和智能的监测机制&#xff0c;为用户提供了便捷、高效的电池使用体验。 Batteries for Mac(Mac电池)v2.2.9直装版下载 首先&#xff0c;Batteries for Mac具备实时电池监测功能&…