記錄我在項(xiàng)目中sharding分庫分表在落地方案:自動分庫 自動按年月建表存儲與查詢

配置文件:bootstrap.yml

# Tomcat
server:
  port: 9528

# Spring
spring:
  application:
    # 應(yīng)用名稱
    name: jingce-sharding-gz
  profiles:
    # 環(huán)境配置
     active: dev

props:
  sql-show: true

配置文件: bootstrap-dev.yml

# Spring
spring:
  ### 處理連接池沖突 #####
  main:
    allow-bean-definition-overriding: true
  datasource:
    driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
    url: jdbc:shardingsphere:classpath:sharding-dev.yaml

  cloud:
    nacos:
      discovery:
        # 服務(wù)注冊地址
        server-addr: 172.16.7.100:8848
#        server-addr: 127.0.0.1:8848
      config:
        # 配置中心地址
        server-addr: 172.16.7.100:8848
#        server-addr: 127.0.0.1:8848
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-dataids: application-dev.${spring.cloud.nacos.config.file-extension}

logging:
  level.root: info
  level.com.jingce: debug

pagehelper:
  helperDialect: postgresql

配置文件sharding.dev.yaml

dataSources:
  abc:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    jdbcUrl: jdbc:mysql://172.16.7.100:3306/jingce_sharding_abc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: wervn11l_2Low0OZq

  ccb:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    jdbcUrl: jdbc:mysql://172.16.7.100:3306/jingce_sharding_ccb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: wervn11l_2Low0OZq

rules:
- !SHARDING
  tables:
    case_follow:
      actualDataNodes: abc.case_follow,ccb.case_follow
      tableStrategy:
        standard:
          shardingColumn: create_time
          shardingAlgorithmName: auto-custom
      databaseStrategy:
        standard:
          shardingColumn: sys_code
          shardingAlgorithmName: auto-custom-db

  shardingAlgorithms:
    auto-custom:
      type: CLASS_BASED
      props:
        strategy: standard
        algorithmClassName: com.jingce.sharding.config.TimeShardingAlgorithm
    auto-custom-db:
      type: CLASS_BASED
      props:
        strategy: standard
        algorithmClassName: com.jingce.sharding.config.TimeShardingAlgorithmDb
        createTable:
          jingce_debt_abc:
            dbName: abc
            jdbcUrl: jdbc:mysql://172.16.7.100:3306/jingce_sharding_abc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
            username: root
            password: wervn11l_2Low0OZq
          jingce_debt_ccb:
            dbName: ccb
            jdbcUrl: jdbc:mysql://172.16.7.100:3306/jingce_sharding_ccb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
            username: root
            password: wervn11l_2Low0OZq

props:
  sql-show: true

配置文件項(xiàng)目圖:


11.png

實(shí)體類

package com.jingce.sharding.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.Date;

/**
 * <p>
 *
 * </p>
 *
 * @author ywl
 * @since 2023-12-05
 */
@Data
public class CaseFollow {

    /**
     * id
     */
    private Long id;

    /**
     * 部門id
     */
    private Long deptId;


    /**
     * 創(chuàng)建時(shí)間(跟進(jìn)時(shí)間)
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;



    @TableField(exist = false)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date startTime;

    @TableField(exist = false)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date endTime;

}

本地線程工具類:threadLocal,在分庫分表實(shí)際代碼中需要使用

package com.jingce.sharding.config;

import java.util.Map;

public class ThreadLocal {

    /**
     * 構(gòu)造函數(shù)私有
     */
    private ThreadLocal() {
    }

    private static final java.lang.ThreadLocal<Map<String, String>> threadLocal = new java.lang.ThreadLocal<>();

    /**
     * 清除用戶信息
     */
    public static void clear() {
        threadLocal.remove();
    }

    /**
     * 存儲用戶信息
     */
    public static void set(Map<String, String> map) {
        threadLocal.set(map);
    }

    /**
     * 獲取當(dāng)前用戶信息
     */
    public static Map<String, String> get() {
        return threadLocal.get();
    }




}

準(zhǔn)備工作做好,下面開始實(shí)現(xiàn)具體分庫分表操作柒莉,以及按月自動建表操作

分庫實(shí)現(xiàn)類:TimeShardingAlgorithmDb,根據(jù)字段配置中的sysCode實(shí)現(xiàn)分庫

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jingce.sharding.config;

import com.jingce.sharding.utils.SpringUtil;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
import org.springframework.core.env.Environment;

import java.sql.*;
import java.time.format.DateTimeFormatter;
import java.util.*;


/**
 * <p> @Title TimeShardingAlgorithm
 * <p> @Description 分片算法闻坚,按月分片
 *
 * @author ACGkaka
 * @date 2022/12/20 11:33
 */

@Slf4j
public class TimeShardingAlgorithmDb implements StandardShardingAlgorithm<String>, ShardingAutoTableAlgorithm {


    /** 表分片符號,例:t_user_202201 中常柄,分片符號為 "_" */
    private static final String TABLE_SPLIT_SYMBOL = "_";



    /** 配置文件路徑 */
    private static final String CONFIG_FILE = "sharding-tables.yaml";


    /**
     * 分片時(shí)間格式
     */
    private static final DateTimeFormatter TABLE_SHARD_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");

    /**
     * 完整時(shí)間格式
     */
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");


    @Getter
    private Properties props;

    @Getter
    private int autoTablesAmount;

    private static String CREATE_TABLE_DB = "createTable";
    private static String DB_NAME = "dbName";


    @Override
    public void init(final Properties dataSources) {
        this.props = dataSources;
    }


    @SneakyThrows
    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<String> preciseShardingValue) {
        String value = preciseShardingValue.getValue();
        log.info(">>>>>>>>>> 【INFO】精確DB分片鲤氢,節(jié)點(diǎn)配置表名:{}", availableTargetNames);

        Environment env = SpringUtil.getBean(Environment.class);
        String property = env.getProperty("spring.dataSources.abc.username");
        System.out.println(property);


        // 獲取需要?jiǎng)?chuàng)建新表的數(shù)據(jù)庫連接
        String createTable = props.getProperty(CREATE_TABLE_DB);
        Map<String, Map<String, String>> map = splitWithoutBraces(createTable);
        System.out.println(map);

        // 獲取需要?jiǎng)?chuàng)建表的數(shù)據(jù)庫信息
        Map<String, String> dataSourceMap = map.get(value);
        ThreadLocal.set(dataSourceMap);
        String dbName = dataSourceMap.get(DB_NAME);



        for (Map.Entry<String, Map<String, String>> entry : map.entrySet()) {
            Map<String, String> mapValue = entry.getValue();
            String logicTableName = preciseShardingValue.getLogicTableName();
            String jdbcUrl = mapValue.get("jdbcUrl");
            String username = mapValue.get("username");
            String password = mapValue.get("password");
            List<String> allTableNameBySchema = getAllTableNameBySchema(logicTableName, jdbcUrl, username, password);
            availableTargetNames.addAll(allTableNameBySchema);
            String key = entry.getKey();
            if (!availableTargetNames.contains(key)){
                availableTargetNames.add(key);
            }
        }

        return dbName;

    }


    public static Map<String, Map<String, String>> splitWithoutBraces(String input) {
        // 去掉收尾大括號
        input = input.replaceFirst("\\{", "").replaceFirst("\\}$", "");
        List<String> list = new ArrayList<>();
        int braceLevel = 0;
        int start = 0;

        for (int i = 0; i < input.length(); i++) {
            char ch = input.charAt(i);
            if (ch == '{') {
                braceLevel++;
            } else if (ch == '}') {
                braceLevel--;
            } else if (ch == ',' && braceLevel == 0) {
                list.add(input.substring(start, i).trim());
                start = i + 1;
            }
        }
        list.add(input.substring(start).trim());
        System.out.println(list);
        Map<String, Map<String, String>> map = new HashMap<>();
        for (String str : list) {
            String[] sp = str.replaceFirst("=", "#@&").split("#@&");
            String key = sp[0];
            String value = sp[1];
            HashMap<String, String> valueMap = new HashMap<>();

            List<String> valueList = Arrays.asList(value.replaceAll("\\{", "").replaceAll("}", "").split(","));
            for (String s : valueList) {
                String[] split = s.replaceFirst("=", "#@&").split("#@&");
                valueMap.put(split[0].trim(),split[1].trim());
            }
            map.put(key.trim(),valueMap);
        }

        return map;
    }


    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<String> rangeShardingValue) {
        log.info(">>>>>>>>>> 【INFO】范圍DB分片,節(jié)點(diǎn)配置表名:{}", availableTargetNames);

        return null;

    }

    @Override
    public String getType() {
        return "auto-custom-db";
    }


//    @Override
//    public Collection<String> doSharding(Collection<String> availableTargetNames, HintShardingValue<String> shardingValue) {
//        List<String> tables = new ArrayList<>();
//        tables.add("ds1");
//        return tables;
//    }


    /**
     * 獲取所有表名
     * @return 表名集合
     * @param logicTableName 邏輯表
     */
    public List<String> getAllTableNameBySchema(String logicTableName,String jdbcUrl,String username,String password) {
        List<String> tableNames = new ArrayList<>();
        if (StringUtils.isEmpty(jdbcUrl) || StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)庫連接配置有誤西潘,請稍后重試,URL:{}, username:{}, password:{}", jdbcUrl, username, password);
            throw new IllegalArgumentException("數(shù)據(jù)庫連接配置有誤哨颂,請稍后重試");
        }
        try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
             Statement st = conn.createStatement()) {
            try (ResultSet rs = st.executeQuery("show TABLES like '" + logicTableName + TABLE_SPLIT_SYMBOL + "%'")) {
                while (rs.next()) {
                    String tableName = rs.getString(1);
                    // 匹配分表格式 例:^(t\_contract_\d{6})$
                    if (tableName != null && tableName.matches(String.format("^(%s\\d{6})$", logicTableName + TABLE_SPLIT_SYMBOL))) {
                        tableNames.add(rs.getString(1));
                    }
                }
            }
        } catch (SQLException e) {
            log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)庫連接失敗喷市,請稍后重試,原因:{}", e.getMessage(), e);
            throw new IllegalArgumentException("數(shù)據(jù)庫連接失敗威恼,請稍后重試");
        }
        return tableNames;
    }

}

分表實(shí)現(xiàn)類:可以根據(jù)實(shí)體類中createTime區(qū)分當(dāng)前數(shù)據(jù)是幾月份并自動按月份建表例如case_follow_202404

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jingce.sharding.config;

import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Range;
import com.jingce.common.core.utils.DateUtils;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;

import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.*;

/**
 * <p> @Title TimeShardingAlgorithm
 * <p> @Description 分片算法品姓,按月分片
 *
 * @author ACGkaka
 * @date 2022/12/20 11:33
 */

@Slf4j
public class TimeShardingAlgorithm implements StandardShardingAlgorithm<String>, ShardingAutoTableAlgorithm {


    /** 表分片符號寝并,例:t_user_202201 中,分片符號為 "_" */
    private static final String TABLE_SPLIT_SYMBOL = "_";



    /** 配置文件路徑 */
    private static final String CONFIG_FILE = "sharding-tables.yaml";


    /**
     * 分片時(shí)間格式
     */
    private static final DateTimeFormatter TABLE_SHARD_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMM");

    /**
     * 完整時(shí)間格式
     */
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");


    @Getter
    private Properties props;

    @Getter
    private int autoTablesAmount;


    @Override
    public void init(final Properties props) {
        this.props = props;
    }


    @SneakyThrows
    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<String> preciseShardingValue) {
        String logicTableName = preciseShardingValue.getLogicTableName();
        log.info(">>>>>>>>>> 【INFO】精確分片腹备,節(jié)點(diǎn)配置表名:{}", availableTargetNames);
        // availableTargetNames.add("case_follow");
        String monthStr = "";

        Object value = preciseShardingValue.getValue();
        if (value instanceof Date){
            System.out.println(111);
            DateFormat dateFormat = new SimpleDateFormat("yyyyMM");
            monthStr = dateFormat.format(value);
        }else if (value instanceof LocalDateTime){
            System.out.println(222);
            LocalDateTime parse = LocalDateTime.parse(value.toString());
            monthStr = parse.format(TABLE_SHARD_TIME_FORMATTER);
        }
        System.out.println(monthStr);
        String resultTableName = logicTableName + "_" + monthStr;

        System.out.println(resultTableName);


        String jdbcUrl = "";
        String username = "";
        String password = "";
        Map<String, String> map = ThreadLocal.get();
        if (ObjectUtil.isNotNull(map)){
            jdbcUrl = map.get("jdbcUrl");
            username = map.get("username");
            password = map.get("password");
            // 用完之后清空ThreadLocal
            ThreadLocal.clear();

            System.out.println(jdbcUrl);
            System.out.println(username);
            System.out.println(password);

            // 查詢催記所有分表節(jié)點(diǎn)
            List<String> allTableNameBySchema = getAllTableNameBySchema(logicTableName,jdbcUrl,username,password);
            System.out.println(allTableNameBySchema);
            for (String table : allTableNameBySchema) {
                if (!availableTargetNames.contains(table)){
                    availableTargetNames.add(table);
                }
            }
//            availableTargetNames.clear();
//            availableTargetNames.addAll(allTableNameBySchema);

            return getShardingTableAndCreate(logicTableName, resultTableName, availableTargetNames, jdbcUrl, username, password);
        }

        return resultTableName;

    }



    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<String> rangeShardingValue) {
        log.info(">>>>>>>>>> 【INFO】范圍分片衬潦,節(jié)點(diǎn)配置表名:{}", availableTargetNames);
        String logicTableName = rangeShardingValue.getLogicTableName();
        List<String> list = new ArrayList<>();
        Range<String> valueRange = rangeShardingValue.getValueRange();
        Object startValue = valueRange.lowerEndpoint();
        Object endValue = valueRange.upperEndpoint();

        String startMonth = "";
        if (startValue instanceof Date){
            DateFormat dateFormat = new SimpleDateFormat("yyyyMM");
            startMonth = dateFormat.format(startValue);
        }else if (startValue instanceof LocalDateTime){
            LocalDateTime parse = LocalDateTime.parse(startValue.toString());
            startMonth = parse.format(TABLE_SHARD_TIME_FORMATTER);
        }

        String endMonth = "";
        if (endValue instanceof Date){
            DateFormat dateFormat = new SimpleDateFormat("yyyyMM");
            endMonth = dateFormat.format(endValue);
        }else if (endValue instanceof LocalDateTime){
            LocalDateTime parse = LocalDateTime.parse(endValue.toString());
            endMonth = parse.format(TABLE_SHARD_TIME_FORMATTER);
        }

        // list.add("case_follow");
        List<String> yearMonthsBetween = DateUtils.getYearMonthsBetween(startMonth, endMonth);
        for (String yearMonth : yearMonthsBetween) {
            String resultTableName =  logicTableName + "_" + yearMonth;
            if (availableTargetNames.contains(resultTableName)){
                list.add(resultTableName);
            }
        }

        return list;

    }

    @Override
    public String getType() {
        return "AUTO_CUSTOM";
    }

    /**
     * 獲取所有表名
     * @return 表名集合
     * @param logicTableName 邏輯表
     */
    public List<String> getAllTableNameBySchema(String logicTableName,String jdbcUrl,String username,String password) {
        List<String> tableNames = new ArrayList<>();
        if (StringUtils.isEmpty(jdbcUrl) || StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)庫連接配置有誤,請稍后重試植酥,URL:{}, username:{}, password:{}", jdbcUrl, username, password);
            throw new IllegalArgumentException("數(shù)據(jù)庫連接配置有誤镀岛,請稍后重試");
        }
        try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
             Statement st = conn.createStatement()) {
            try (ResultSet rs = st.executeQuery("show TABLES like '" + logicTableName + TABLE_SPLIT_SYMBOL + "%'")) {
                while (rs.next()) {
                    String tableName = rs.getString(1);
                    // 匹配分表格式 例:^(t\_contract_\d{6})$
                    if (tableName != null && tableName.matches(String.format("^(%s\\d{6})$", logicTableName + TABLE_SPLIT_SYMBOL))) {
                        tableNames.add(rs.getString(1));
                    }
                }
            }
        } catch (SQLException e) {
            log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)庫連接失敗,請稍后重試友驮,原因:{}", e.getMessage(), e);
            throw new IllegalArgumentException("數(shù)據(jù)庫連接失敗漂羊,請稍后重試");
        }
        return tableNames;
    }

    /**
     * 檢查分表獲取的表名是否存在,不存在則自動建表
     * @param logicTableName   邏輯表
     * @param resultTableName 真實(shí)表名卸留,例:t_user_202201
     * @return 確認(rèn)存在于數(shù)據(jù)庫中的真實(shí)表名
     */
    public String getShardingTableAndCreate(String logicTableName, String resultTableName, Collection<String> availableTargetNames,String jdbcUrl,String username,String password) {
        // 緩存中有此表則返回走越,沒有則判斷創(chuàng)建
        if (availableTargetNames.contains(resultTableName)) {
            return resultTableName;
        } else {
            // 檢查分表獲取的表名不存在,需要自動建表
            boolean isSuccess = createShardingTable(logicTableName, resultTableName,jdbcUrl,username,password);
            if (isSuccess) {
                // 如果建表成功耻瑟,需要更新緩存
                availableTargetNames.add(resultTableName);
                autoTablesAmount++;
                return resultTableName;
            } else {
                // 如果建表失敗旨指,返回邏輯空表
                return logicTableName;
            }
        }
    }

    /**
     * 創(chuàng)建分表2
     * @param logicTableName  邏輯表
     * @param resultTableName 真實(shí)表名,例:t_user_202201
     * @return 創(chuàng)建結(jié)果(true創(chuàng)建成功喳整,false未創(chuàng)建)
     */
    public boolean createShardingTable(String logicTableName, String resultTableName,String jdbcUrl,String username,String password) {
        // 根據(jù)日期判斷淤毛,當(dāng)前月份之后分表不提前創(chuàng)建
        String month = resultTableName.replace(logicTableName + TABLE_SPLIT_SYMBOL,"");
        YearMonth shardingMonth = YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyyMM"));
        if (shardingMonth.isAfter(YearMonth.now())) {
            return false;
        }

        synchronized (logicTableName.intern()) {
            // 緩存中無此表,則建表并添加緩存
            executeSql(Collections.singletonList("CREATE TABLE IF NOT EXISTS `" + resultTableName + "` LIKE `" + logicTableName + "`;"),jdbcUrl,username,password);
        }
        return true;
    }

    /**
     * 執(zhí)行SQL
     * @param sqlList SQL集合
     */
    private void executeSql(List<String> sqlList,String jdbcUrl,String username,String password) {
        if (StringUtils.isEmpty(jdbcUrl) || StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)庫連接配置有誤算柳,請稍后重試低淡,URL:{}, username:{}, password:{}", jdbcUrl, username, password);
            throw new IllegalArgumentException("數(shù)據(jù)庫連接配置有誤,請稍后重試");
        }
        try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {
            try (Statement st = conn.createStatement()) {
                conn.setAutoCommit(false);
                for (String sql : sqlList) {
                    st.execute(sql);
                }
            } catch (Exception e) {
                conn.rollback();
                log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)表創(chuàng)建執(zhí)行失敗瞬项,請稍后重試蔗蹋,原因:{}", e.getMessage(), e);
                throw new IllegalArgumentException("數(shù)據(jù)表創(chuàng)建執(zhí)行失敗,請稍后重試");
            }
        } catch (SQLException e) {
            log.error(">>>>>>>>>> 【ERROR】數(shù)據(jù)庫連接失敗囱淋,請稍后重試猪杭,原因:{}", e.getMessage(), e);
            throw new IllegalArgumentException("數(shù)據(jù)庫連接失敗,請稍后重試");
        }
    }

}

重要:項(xiàng)目啟動后妥衣,需要主動執(zhí)行一次查詢動作皂吮,目的是為了將分庫分表的配置加載到緩存中,
如果內(nèi)存的緩存中沒有分庫分表的配置,查詢會沒有數(shù)據(jù)
詳細(xì)可以參考:https://blog.csdn.net/qq_33204709/article/details/132590731?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-132590731-blog-131208779.235%5Ev38%5Epc_relevant_anti_t3_base&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-132590731-blog-131208779.235%5Ev38%5Epc_relevant_anti_t3_base&utm_relevant_index=1

這個(gè)地址有具體的自動按月分表方案税手,但是我自己的代碼中有根據(jù)項(xiàng)目實(shí)際的分庫并分表存儲數(shù)據(jù)方案蜂筹,可以多多參考達(dá)到自己的目的

package com.jingce.sharding.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jingce.sharding.domain.CaseFollow;
import com.jingce.sharding.service.ICaseFollowService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p> @Title ShardingTablesLoadRunner
 * <p> @Description 項(xiàng)目啟動后,讀取已有分表芦倒,進(jìn)行緩存
 *
 * @author ACGkaka
 * @date 2022/12/20 15:41
 */
@Slf4j
//@Order(value = 100) // 數(shù)字越小艺挪,越先執(zhí)行
@Component
public class ShardingTablesLoadRunner implements CommandLineRunner {

//    @Autowired
//    private UserService userService;


    @Autowired
    private ICaseFollowService caseFollowService;

    @Override
    public void run(String... args) {
        // 讀取已有分表,進(jìn)行緩存
//        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(User::getCreateTime, LocalDateTime.now()).last("limit 1");
//        List<User> list = userService.list(queryWrapper);
//        System.out.println(list);



        LambdaQueryWrapper<CaseFollow> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(CaseFollow::getCreateTime, LocalDateTime.now()).last("limit 1");
        queryWrapper.eq(CaseFollow::getSysCode,"jingce_debt_abc").eq(CaseFollow::getCreateTime, LocalDateTime.now()).last("limit 1");
        List<CaseFollow> list = caseFollowService.list(queryWrapper);
        System.out.println(list);


        log.info(">>>>>>>>>> 【ShardingTablesLoadRunner】緩存已有分表成功 <<<<<<<<<<");
    }

}

pom文件:改配置中可能存在項(xiàng)目中自己的一些配置兵扬,不需要可以刪除點(diǎn)

<dependencies>

        <!-- SpringCloud Ailibaba Nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- SpringCloud Ailibaba Nacos Config -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!-- SpringCloud Ailibaba Sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <!-- SpringBoot Actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- Swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.fox.version}</version>
        </dependency>

        <!-- Mysql Connector -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- RuoYi Common Datascope -->
        <dependency>
            <groupId>com.jingce</groupId>
            <artifactId>jingce-common-datascope</artifactId>
        </dependency>

        <!-- RuoYi Common Log -->
        <dependency>
            <groupId>com.jingce</groupId>
            <artifactId>jingce-common-log</artifactId>
        </dependency>

        <!-- RuoYi Common Swagger -->
        <dependency>
            <groupId>com.jingce</groupId>
            <artifactId>jingce-common-swagger</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.8.3</version>
            <scope>compile</scope>
        </dependency>


        <!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>

        <!-- Sharding-JDBC -->
        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core</artifactId>
            <version>5.3.0</version>
        </dependency>

        <!-- Mybatis的分頁插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
        </dependency>

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


    </dependencies>

項(xiàng)目架構(gòu)圖:


22.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麻裳,一起剝皮案震驚了整個(gè)濱河市口蝠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌津坑,老刑警劉巖妙蔗,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疆瑰,居然都是意外死亡眉反,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門乃摹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來禁漓,“玉大人,你說我怎么就攤上這事孵睬〔ゼ撸” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵掰读,是天一觀的道長秘狞。 經(jīng)常有香客問我,道長蹈集,這世上最難降的妖魔是什么烁试? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮拢肆,結(jié)果婚禮上减响,老公的妹妹穿的比我還像新娘。我一直安慰自己郭怪,他們只是感情好支示,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鄙才,像睡著了一般颂鸿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上攒庵,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天嘴纺,我揣著相機(jī)與錄音,去河邊找鬼浓冒。 笑死栽渴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的裆蒸。 我是一名探鬼主播熔萧,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼僚祷!你這毒婦竟也來了佛致?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤辙谜,失蹤者是張志新(化名)和其女友劉穎俺榆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體装哆,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罐脊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蜕琴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萍桌。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凌简,靈堂內(nèi)的尸體忽然破棺而出上炎,到底是詐尸還是另有隱情,我是刑警寧澤雏搂,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布藕施,位于F島的核電站,受9級特大地震影響凸郑,放射性物質(zhì)發(fā)生泄漏裳食。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一芙沥、第九天 我趴在偏房一處隱蔽的房頂上張望诲祸。 院中可真熱鬧,春花似錦而昨、人聲如沸救氯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽径密。三九已至,卻和暖如春躺孝,著一層夾襖步出監(jiān)牢的瞬間享扔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工植袍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惧眠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓于个,卻偏偏與公主長得像氛魁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 搜了下,一部分是說講清單文件加個(gè)東西:https://blog.csdn.net/u011343735/artic...
    javalong閱讀 311評論 0 0
  • 1 工程創(chuàng)建和配置 簽名配置問題1 由于項(xiàng)目是從uniapp離線打包工程來的或链,所以有些配置是已經(jīng)存在的惫恼。創(chuàng)建工程時(shí)...
    司空洛一閱讀 1,371評論 0 0
  • 工作中發(fā)現(xiàn)了個(gè)私有倉庫 是在內(nèi)網(wǎng)環(huán)境,上傳了個(gè)jar 結(jié)果沒有成功特來學(xué)習(xí)以下想用docker的方式進(jìn)行安裝 1....
    請叫我翟先生閱讀 339評論 0 0
  • Task 06 SQL高級處理 Content 窗口函數(shù) GROUPING運(yùn)算符 存儲過程和參數(shù) 預(yù)處理聲明PRE...
    yuiki_0829閱讀 314評論 0 0
  • 語言技能 JAVA基礎(chǔ) 操作符澳盐、控制執(zhí)行流程JAVA的重要特性:自動內(nèi)存管理機(jī)制祈纯、異常處理。 ArrayList的...
    emperorxiaomai閱讀 447評論 0 0