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

根据如下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。 多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Jolt Json转换工具的基础教程

Jolt Json转换工具 jolt是一个轻量级的json文件转换库&#xff0c;可以把输入的json按照你编写脚本模板输出成你想要的json文本&#xff0c;能实现同样功能的有我们常用的velocity模板引擎&#xff0c;但jolt跟轻量且更专注于json&#xff0c;且在实现一些简单的格式转换中&am…

怎么样零代码零成本搭建个人网站

先申明 为了避免有标题党的嫌疑&#xff0c;这里先做申明。 标题中说的零代码指的是借助VuePress 通过简单配置&#xff0c;帮助我们生成静态网站。 零成本指的是借助GitHub Pages 或者Gitee Pages 部署VuePress生成的静态网站。让互联网上的小伙伴访问到我们的个人网站。 …

基础知识集合

https://blog.csdn.net/sheng_q/category_10901984.html?spm1001.2014.3001.5482 字节流&#xff1a;面向字节的io流&#xff0c;音频 图片 歌曲 byteArray/stringbuffer/file/piped/sequence /filter/data/buffer缓冲/lineNumber/pushedbackInputStream byte/file/piped/…

第十二届蓝桥杯C/C++ B组 杨辉三角形(二分查找+思维)

3418. 杨辉三角形 - AcWing题库 题目描述: 思路&#xff1a; 从上图片中&#xff0c;我们可以看出来这是一个对称图形&#xff0c;所以我们只看左半部分就可以了&#xff0c;我们一行一列去做数据量是1e9这样会很麻烦&#xff0c;所以我们这里做一个思想转换&#xff0c;斜着…

打破国外垄断|暴雨发布纯血国产电脑

要说现在国产手机这边已然进入纯自研模式&#xff0c;但电脑这边却还是仍未打破国外技术垄断。但就在刚刚&#xff0c;暴雨发布自研架构台式机open Station X &#xff0c;这是纯血鸿蒙系统之后国产又一款纯血产品发布&#xff01;标志的我们已经彻底打破西方在硬件及软件方面的…

vulfocus靶场thinkphp命令执行cve-2018-1002015

thinkPHP 5.0.x版本和5.1.x版本中存在远程代码执行漏洞&#xff0c;该漏洞源于ThinkPHP在获取控制器名时未对用户提交的参数进行严格的过滤。远程攻击者可通过输入‘&#xff3c;’字符的方式调用任意方法利用该漏洞执行代码 开启靶场&#xff1a; 使用工具&#xff1a; think…

NewStarCTF 2023 web

目录 week1 泄漏的秘密 Begin of Upload Begin of HTTP ErrorFlask Begin of PHP R!C!E! EasyLogin week2 游戏高手 include 0。0 ez_sql Unserialize&#xff1f; Upload again! R!!C!!E!! week3 Include &#x1f350; medium_sql POP Gadget GenShin wee…

JDBC学习

DriverManager&#xff08;驱动管理类&#xff09; Drivermanager的作用有&#xff1a; 1.注册驱动&#xff1b; 2.获取数据库连接 Class.forName("com.mysql.cj.jdbc.Driver"); 这一行的作用就是注册Mysql驱动&#xff08;把我们下载的jar包加载到内存里去&…

使用easyexcel将csv转为excel

一.背景 供应商系统下载的csv文件不支持域控&#xff08;主要是第三方wps服务不能对csv文件加密&#xff0c;但是可以对office系列产品进行权限访问的加密控制&#xff09;。因此思路就改为现将csv文件转为excel文件&#xff0c;然后对excel文件进行加域控制。本文主要介绍如何…

基于IIoT的设备预测性维护设计

基于IIoT的设备预测性维护设计 一、引言 在工业物联网&#xff08;IIoT&#xff09;的背景下&#xff0c;设备预测性维护成为了一种关键的战略&#xff0c;能够帮助企业提前发现并解决设备故障&#xff0c;从而提高生产效率、减少停机时间&#xff0c;并降低总体维护成本。为了…

理解JMM

JMM 对volatile的理解 volatile 是java虚拟机提供轻量级的同步机制 1、保证可见性 2、不保证原子性 3、禁止指令重排 那么可见性与JMM相关 什么是JMM Java内存模型&#xff0c;不存在的东西&#xff0c;是一个概念&#xff0c;是一个约定 线程加锁前&#xff0c;必须读取…

【002_音频开发_基础篇_Linux音频架构简介】

002_音频开发_基础篇_Linux音频架构简介 文章目录 002_音频开发_基础篇_Linux音频架构简介创作背景Linux 音频架构ALSA 简介ASoC 驱动硬件架构软件架构MachinePlatformCodec ASoC 驱动 PCMALSA设备文件结构 ALSA 使用常用概念alsa-libALSA Open 流程ALSA Write 流程2种写入方法…

基础SQL DDL语句

MySQL的DDL&#xff08;Data Definition Language&#xff09;语句用于定义或修改数据库结构。 DDL数据库操作 查看所有的数据库 show databases; 红色圈起来的是系统数据库&#xff0c;是系统自带的 mysql&#xff1a;包含存储MySQL服务器运行时所需信息的表。这包括数据字典…

如何利用pg_dump和pg_restore迁移从一个PostgreSQL服务器到另一个服务器,同时保持一致性与高效性?

文章目录 解决方案1. 使用pg_dump导出数据2. 将导出的数据复制到目标服务器3. 使用pg_restore导入数据保持一致性与高效性的策略一致性高效性 示例代码导出数据复制数据到目标服务器在目标服务器上解压并导入数据 PostgreSQL数据库的迁移是一个常见的任务&#xff0c;特别是在升…

用Vue全家桶手工搓了一个高仿抖音源码 全开源

用Vue全家桶手工搓了一个高仿抖音&#xff0c;全开源 PC浏览器请用手机模式访问。先按F12调出控制台&#xff0c;再按CtrlShiftM切换到手机模式&#xff0c;手机请用Via浏览器或者Chrome浏览器预览。其他浏览器会强制将视频全屏&#xff0c;导致样式都失效。 运行项目&#x…

【C++】STL:vector常用接口的使用和模拟实现

Hello everybody!这篇文章主要给大家讲讲vector常用接口的模拟实现&#xff0c;STL库中的实现一层套着一层&#xff0c;十分复杂&#xff0c;目前阶段还不适合看源代码。而模拟实现可以让我们从底层上了解这些接口的原理从而更好的使用这些接口。另外我还会讲一些在vector使用过…

【第34天】SQL进阶-SQL高级技巧-Window Funtion(SQL 小虚竹)

回城传送–》《100天精通MYSQL从入门到就业》 文章目录 零、前言一、练习题目二、SQL思路初始化数据什么是Window Funtion窗口函数的分类语法结构第一种写法&#xff1a;第二种写法&#xff1a; 实战体验序号函数&#xff1a;row_number()序号函数&#xff1a;rank()序号函数&…

【树莓派Linux内核开发】入门实操篇(虚拟机Ubuntu环境搭建+内核源码获取与配置+内核交叉编译+内核镜像挂载)

【树莓派Linux内核开发】入门实操篇&#xff08;虚拟机Ubuntu环境搭建内核源码获取与配置内核交叉编译内核镜像挂载&#xff09; 文章目录 【树莓派Linux内核开发】入门实操篇&#xff08;虚拟机Ubuntu环境搭建内核源码获取与配置内核交叉编译内核镜像挂载&#xff09;一、搭建…

什么是0-day漏洞,怎么防护0-day漏洞攻击

随着信息技术的快速发展&#xff0c;网络安全问题日益凸显&#xff0c;其中0day漏洞攻击作为一种高级威胁手段&#xff0c;给企业和个人用户带来了极大的风险。下面德迅云安全就对0day漏洞攻击进行简单讲解下&#xff0c;并分享相应的一些安全措施&#xff0c;以期提高网络安全…

网络空间地图测绘理论体系白皮书(2023年)02网络空间测绘研究背景(想法比较好,着重看)

01前言 02 网络空间测绘研究背景 2.1 网络空间的起源 2.2 传统测绘理论 2.3 网络空间测绘相关工作 03 测绘体系框架概念定义 3.1 网络空间 3.2 网络空间地图测绘 3.3 体系框架总体思路 04 测绘体系框架应用实践 4.1 网络空间地形图 4.2 网络空间地志图 4.3 网络空间战略图 05 总…