ShardingSphere项目快速启动

411 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

ShardingSphere5.2.0发布有一段时间了,包含了很多新的特性,新版本在功能、性能、测试、文档、示例等方面都进行了大量的优化。接下来我们就用数篇文章来介绍ShardingSphere5.2.0的使用。

1.项目准备

我们采用如下几个环境进行准备,jdk的话我们进行了升级,采用JDK11进行开发

  • 开发工具:IntelliJIdea

  • 数据库:mysql 8.X

  • 框架:Springboot

  • JDK版本: 11

2.数据库准备

新建两个数据库,db1、db2,并在这两个数据库分辨新建t_order_0、t_order_1这两个表,建表语句如下:

#第一个数据库
create database db1;
use db1;
create table db1.t_order_0
(
	order_id bigint not null comment 'order_id'
		primary key,
	user_id bigint not null comment '用户id'
);
create table db1.t_order_1
(
	order_id bigint not null comment 'order_id'
		primary key,
	user_id bigint not null comment '用户id'
);
#第二个数据库
create database db2;
use db2;
create table db2.t_order_0
(
	order_id bigint not null comment 'order_id'
		primary key,
	user_id bigint not null comment '用户id'
);
create table db2.t_order_1
(
	order_id bigint not null comment 'order_id'
		primary key,
	user_id bigint not null comment '用户id'
);

3.用Idea快速搭建一个项目

本本文章是基于ShardingSphere最新的版本5.2.0搭建,首先我们点击idea的File->New->Project新建一个项目。

然后点击Next

引入项目相关依

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.daiyu</groupId>
    <artifactId>ShardingSphere-Learn</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ShardingSphere-Learn</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.5.6</spring-boot.version>
        <mybatis-plus.version>3.5.2</mybatis-plus.version>
        <knife4j.version>3.0.3</knife4j.version>
        <sharding.version>5.2.0</sharding.version>
        <druid.version>1.2.9</druid.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <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>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>${knife4j.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!--sharding相关依赖-->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version>${sharding.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.daiyu.sharding.ShardingSphereLearnApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

3.接下来简单的配置下Sharidng的分库分表的策略

在项目的application.yml配置分库分表的策略,详细配置如下:

server.port=8080
spring.application.name=ShardingSphere-Learn
#knife4j
knife4j.enable=true
#mybatis-plus
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.mapper-locations=classpath:**/*.xml
mybatis-plus.type-aliases-package=com.daiyu.sharding.domain.entity
#sharidng的数据库连接配置
spring.shardingsphere.datasource.ds-1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-1.password=123456
spring.shardingsphere.datasource.ds-1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-1.url=jdbc:mysql://localhost:3308/db1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.shardingsphere.datasource.ds-1.username=root

spring.shardingsphere.datasource.ds-2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds-2.password=123456
spring.shardingsphere.datasource.ds-2.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-2.url=jdbc:mysql://localhost:3308/db2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.shardingsphere.datasource.ds-2.username=root

spring.shardingsphere.datasource.names=ds-1,ds-2
spring.shardingsphere.props.sql-show=true

spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-name=database-inline
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-column=user_id
#sharding的分片算法
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.props.algorithm-expression=ds-$->{user_id % 2 +1}
spring.shardingsphere.rules.sharding.sharding-algorithms.database-inline.type=INLINE

spring.shardingsphere.rules.sharding.sharding-algorithms.table-inline.props.algorithm-expression=t_order_$->{order_id % 2}
spring.shardingsphere.rules.sharding.sharding-algorithms.table-inline.type=INLINE

spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=ds-$->{1..2}.t_order_$->{0..1}
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-algorithm-name=table-inline
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-column=order_id
spring.shardingsphere.rules.sharding.binding-tables=t_order

4.编写实体类

package com.daiyu.sharding.domain.entity;

import lombok.Data;

@Data
public class Order {
    /**
     * order_id
     */
    private Long orderId;

    /**
     * 用户id
     */
    private Long userId;

}

5.编写service

package com.daiyu.sharding.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.daiyu.sharding.domain.entity.Order;
import com.daiyu.sharding.domain.request.OrderReq;
import com.daiyu.sharding.domain.response.OrderRsp;
import com.daiyu.sharding.mapper.OrderMapper;
import com.daiyu.sharding.service.OrderService;
import kotlin.jvm.internal.Lambda;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Array;
import java.util.ArrayList;
import java.util.List;

/**
 * @author :chenlong
 * @filename OrderServiceImpl
 * @date 2022-09-12 16:57
 * @description:orderservice实现类
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private OrderMapper orderMapper;

    @Override
    public List<OrderRsp> getOrderInfo() {
        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<Order>();
        List<Order> list = orderMapper.selectList(queryWrapper);
        List<OrderRsp> orderList = new ArrayList<>();
        list.stream().forEach(order -> {
            OrderRsp orderRsp = new OrderRsp();
            BeanUtils.copyProperties(order, orderRsp);
            orderList.add(orderRsp);
        });
        return orderList;
    }

    @Override
    public int insertOrder(Order order) {
        return orderMapper.insert(order);
    }

}

6.编写controller

package com.daiyu.sharding.controller;

import com.daiyu.sharding.common.core.JsonResult;
import com.daiyu.sharding.domain.entity.Order;
import com.daiyu.sharding.domain.response.OrderRsp;
import com.daiyu.sharding.service.OrderService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author :daiyu
 * @filename OrderController
 * @date 2022-09-12 16:59
 * @description:
 */
@Slf4j
@Api(tags = "订单相关接口")
@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private OrderService orderService;

    @ApiOperationSupport(author = "daiyu")
    @ApiOperation(value = "查询订单", notes = "查询订单")
    @GetMapping("/search")
    public JsonResult<List<OrderRsp>> getOrderInfo() {
        List<OrderRsp> orderInfo = orderService.getOrderInfo();
        JsonResult<List<OrderRsp>> jsonResult = new JsonResult<>();
        jsonResult.setData(orderInfo);
        return jsonResult;
    }

    @ApiOperationSupport(author = "daiyu")
    @ApiOperation(value = "添加订单", notes = "添加订单")
    @PostMapping("/add")
    public JsonResult<Integer> addOrderInfo(Order order) {
        int result = orderService.insertOrder(order);
        JsonResult<Integer> jsonResult = new JsonResult<>();
        jsonResult.setData(result);
        return jsonResult;
    }
}

7.编写Knife4j配置类

package com.daiyu.sharding.config;


import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;


/**
 * @author :daiyu
 * @filename Knife4jConfig
 * @date 2022-04-23 16:49
 * @description:doc配置
 */
@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class Knife4jConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.daiyu.sharding.controller"))
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .paths(PathSelectors.regex("(?!/error.*).*"))
                .build();

    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .description("接口测试文档")
                .contact(new Contact("beyourself", "https://www", "xxx@qq.com"))
                .version("v1.0")
                .title("API测试文档")
                .build();
    }
}

8.编写统一返回

package com.daiyu.sharding.common.core;

import com.daiyu.sharding.common.exception.BaseErrorCodeEnum;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;

/**
 * 统一的Spring mvc响应结果封装对象
 *
 * @author daiyu
 * @version 1.0
 */
@Slf4j
public class JsonResult<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 请求成功
     */
    private static final boolean REQUEST_SUCCESS = true;

    /**
     * 请求失败
     */
    private static final boolean REQUEST_FAIL = false;

    /**
     * 默认错误码
     */
    private static final String DEFAULT_ERROR_CODE = "-1";

    /**
     * 请求是否成功
     */
    private Boolean success;

    /**
     * 业务数据
     */
    private T data;

    /**
     * 错误码
     */
    private String errorCode;

    /**
     * 错误提示语
     */
    private String errorMessage;


    public JsonResult() {
    }

    public JsonResult(Boolean success, T data, String errorCode, String errorMessage) {
        this.success = success;
        this.data = data;
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    /**
     * 成功,不用返回数据
     *
     * @return
     */
    public static <T> JsonResult<T> buildSuccess() {
        return new JsonResult<>(REQUEST_SUCCESS, null, null, null);
    }

    /**
     * 成功,返回数据
     *
     * @param data
     * @return
     */
    public static <T> JsonResult<T> buildSuccess(T data) {
        return new JsonResult<>(REQUEST_SUCCESS, data, null, null);
    }

    /**
     * 失败,固定状态码
     *
     * @param errorMsg
     * @return
     */
    public static <T> JsonResult<T> buildError(String errorMsg) {
        return new JsonResult<>(REQUEST_FAIL, null, DEFAULT_ERROR_CODE, errorMsg);
    }

    /**
     * 失败,自定义错误码和信息
     *
     * @param errorCode 错误码
     * @param errorMsg  错误提示
     * @return
     */
    public static <T> JsonResult<T> buildError(String errorCode, String errorMsg) {
        return new JsonResult<>(REQUEST_FAIL, null, errorCode, errorMsg);
    }

    /**
     * 失败,枚举类定义错误码和信息
     *
     * @param baseErrorCodeEnum
     * @return
     */
    public static <T> JsonResult<T> buildError(BaseErrorCodeEnum baseErrorCodeEnum) {
        return new JsonResult<>(REQUEST_FAIL, null, baseErrorCodeEnum.getErrorCode(), baseErrorCodeEnum.getErrorMsg());
    }

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }
}

项目结构大致如下

9.运行下看效果

项目启动后的,在浏览器输入http://localhost:8080/doc.html,大致界面如下

发送请求,分别发送如下请求

#第一个请求
{
  "orderId": 1,
  "userId": 1
}
#第二个请求
{
  "orderId": 1,
  "userId": 2
}
#第三个请求
{
  "orderId": 2,
  "userId": 1
}
#第四个请求
{
  "orderId": 2,
  "userId": 2
}

然后idea控制台打印的日志

说名sharding已经将sql路由到对应的表

到此,我们的第一个ShardingSphere的demo启动完毕。