看完这篇,别再说不会Spring 分库分表了

多数据源,读写分离,分库分表,基本上已经是现在任何一个项目的基本配置了,在之前的文章
Spring多数据源实现icon-default.png?t=N6B9https://blog.csdn.net/wangerrong/article/details/131910740  里讲了多数据源的实现,其实已经包含了读写分离(master和slave分别配置主库和只读库就好了),现在就记录下分库分表的实现过程。

1,引入jdbc, mybatis, shardingsphere等依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <version>2.4.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>8.0.30</version>
</dependency>
<!-- jpa持久化工具 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>2.7.6</version>
</dependency>
<!-- 必须引入的包 ShardingSphere -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.2.0</version>
</dependency>

2,建立数据库和数据表

 

3,添加分库分表配置到bootsrap.yml

server:
  port: 9102
# NaCos
spring:
  application:
    name: deviceservice
  shardingsphere:
    # 数据源配置
    datasource:
      # 数据源名称,多数据源以逗号分隔
      names: db0,db1
      db0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://xxxx:3306/db_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
        username: root
        password: xxxxxxxxx
      db1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://yyyy:3306/db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
        username: root
        password: yyyyyyyyy
    # 分片规则配置
    rules:
      sharding:
        # 分片算法配置
        sharding-algorithms:
          database-inline:
            # 分片算法类型
            type: INLINE
            props:
              # 分片算法的行表达式(算法自行定义,此处为方便演示效果)
              algorithm-expression: db$->{order_id%10 > 4?1:0}
              # 关键,查询时是否在所有分库分表中查询
              allow-range-query-with-inline-sharding: true
          table-inline:
            # 分片算法类型
            type: INLINE
            props:
              # 分片算法的行表达式
              algorithm-expression: t_order_$->{order_id % 3}
              # 关键,查询时是否在所有分库分表中查询
              allow-range-query-with-inline-sharding: true
        tables:
          # 逻辑表名称
          t_order:
            # 行表达式标识符可以使用 ${...} 或 $->{...},但前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 $->{...}
            actual-data-nodes: db${0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
              standard:
                # 分片列名称
                sharding-column: order_id
                # 分片算法名称
                sharding-algorithm-name: database-inline
            # 分表策略
            table-strategy:
              standard:
                # 分片列名称
                sharding-column: order_id
                # 分片算法名称
                sharding-algorithm-name: table-inline
    # 属性配置
    props:
      # 展示修改以后的sql语句
      sql-show: true
  profiles:
    active: dev
---
spring:
  config:
    activate:
      on-profile: dev
    import: optional:config\application-dev.yml

4,  实体类和mapper

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_order")
public class Order {
    private long orderId;
    private String createdTime;
}
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_device")
public class Device {
    private long deviceId;
    private String name;
    private String createdTime;
}

 

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.domain.Order;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface OrderMapper extends BaseMapper<Order> {

}
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.domain.Device;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface DeviceMapper extends BaseMapper<Device> {
}

 


import com.xxx.domain.Order;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public interface OrderService {
    public void saveOrder(Order order);

    public List<Order> list();

    public void delete(long orderId);

    public void update(long orderId);
}
import com.xxx.domain.Device;
import org.springframework.stereotype.Service;

@Service
public interface DeviceService {
    public void saveDevice(Device device);
}

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxx.domain.Order;
import com.xxx.mapper.OrderMapper;
import com.xxx.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Override
    public void saveOrder(Order order) {
        orderMapper.insert(order);
    }

    @Override
    public void delete(long orderId) {
        QueryWrapper qw = new QueryWrapper<Order>();
        qw.eq("order_id",orderId);
        orderMapper.delete(qw);
    }

    @Override
    public void update(long orderId) {
        Order order = new Order();
        order.setOrderId(orderId);
        order.setCreatedTime("2200-07-26 00:00:01");

        QueryWrapper qw = new QueryWrapper<Order>();
        qw.eq("order_id",orderId);
        orderMapper.update(order,qw);
    }


    @Override
    public List<Order> list() {
        QueryWrapper qw = new QueryWrapper<Order>();
        qw.ge("order_id",0);
        qw.orderByAsc("order_id");
        return orderMapper.selectList(qw);
    }
}
import com.xxx.domain.Device;
import com.xxx.mapper.DeviceMapper;
import com.xxx.service.DeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void saveDevice(Device device) {
        deviceMapper.insert(device);
    }
}

import com.xxx.common.UserContext;
import com.xxx.domain.Device;
import com.xxx.domain.Order;
import com.xxx.service.DeviceService;
import com.xxx.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@RestController
@RefreshScope
@Slf4j
@RequestMapping("/device")
public class DeviceController extends AbstractController{
    @Autowired
    private OrderService orderService;
    @Autowired
    private DeviceService devieService;

    @GetMapping("/save")
    public String save(@RequestParam("orderId") int orderId){
        Order order = new Order();
        order.setOrderId(orderId);
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String dateStr = sdf.format(new Date());
        order.setCreatedTime(dateStr);
        orderService.saveOrder(order);

        Device device = new Device();
        device.setDeviceId(orderId);
        device.setName(orderId+"_"+dateStr);
        device.setCreatedTime(dateStr);
        devieService.saveDevice(device);

        return "success";
    }

    @GetMapping("/delete")
    public String delete(@RequestParam("orderId") long orderId) {
        orderService.delete(orderId);
        return "success";
    }

    @GetMapping("/update")
    public String update(@RequestParam("orderId") int orderId) {
        orderService.update(orderId);
        return "success";
    }

    @GetMapping("/list")
    public List<Order> list() {
        return orderService.list();
    }
}

上面代码是一个简单的验证:

1,  通过对做了分库分表配置的t_order表的增删改查,验证分库分表后的增删改查是否生效,验证通过

2,验证对没做分库分表配置的t_device表的增加,验证正常数据库操作(默认走spring.shardingsphere.datasource.names: db0,db1配置里的第一个数据库)是否生效,验证通过

5,总结

Springboot + shardingsphere 实现分库分表的需求,比较简单,但是要想真正地投入实用,还有很多路要走,比如实现自定义分库分表规则的算法,自定义分布式表的主键ID,基于分库分表后的排序(默认已实现按分库分表的列进行排序)和分页等等等。

码字不易,记得点赞关注哟!

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东皋长歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值