springboot2.7集成sharding-jdbc4.1.1实现业务分表

1、引入maven

        <dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.1.1</version></dependency>

2、基本代码示例

基本逻辑:利用数据库存在的租户uuid,做租户级别的数据分表,如 user_${uuid},order_${uuid}等,因为好像pgsql无法支持使用 “-”这个特殊字符做为表名,所以需要吧uuid中的 - 全部替换掉

DynamicTableConfig.java

用于初始化动态分表信息

MybatisPlusConfig.java

sql拦截器,针对所有插入,查询和更新,判断所用sql是否属于分表范围内

OrgAutoShardingSphereFixture.java

自定义分片算法,继承实现Hint分片,用于动态分表

ShardingAlgorithmTool

动态分表工具类

ShardingTablesLoadRunner

项目启动后 读取已有分表 进行缓存

SqlParserHandler

sql工具类

TablesNamesConfig

分表信息和sql集合类,所需要做分表的,均需要配置在这里

EdgeUserAndOrderServiceInterceptor做sql拦截器

TablesNamesConfig类:
public class TablesNamesConfig {
//这里是你要做分表的表名public final static String TABLES_NAMES = "edge_cs_user,edge_order_info";/*** 模板sql** @param tableName* @return*/public static List<String> selectTableCreateSql(String tableName) {List<String> res = new ArrayList<>();if (tableName.equals("edge_cs_user")) {res.add("替换成你要创建的sql语句");} else if (tableName.equals("edge_order_info")) {res.add("替换成你要创建的sql语句");}return res;}
}
SqlParserHandler类
import com.baomidou.mybatisplus.core.injector.methods.Insert;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.create.index.CreateIndex;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.create.view.CreateView;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.execute.Execute;
import net.sf.jsqlparser.statement.merge.Merge;
import net.sf.jsqlparser.statement.replace.Replace;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.truncate.Truncate;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.upsert.Upsert;
import net.sf.jsqlparser.util.TablesNamesFinder;import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;/*** sql解析工具** @Created by xieyaoyi* @Created_date 2023/12/12*/
public class SqlParserHandler {/*** 由于jsqlparser没有获取SQL类型的原始工具,并且在下面操作时需要知道SQL类型,所以编写此工具方法** @param sql sql语句* @return sql类型,* @throws JSQLParserException*/public static String getSqlType(String sql) throws JSQLParserException {Statement sqlStmt = CCJSqlParserUtil.parse(new StringReader(sql));if (sqlStmt instanceof Alter) {return "ALTER";} else if (sqlStmt instanceof CreateIndex) {return "CREATEINDEX";} else if (sqlStmt instanceof CreateTable) {return "CREATETABLE";} else if (sqlStmt instanceof CreateView) {return "CREATEVIEW";} else if (sqlStmt instanceof Delete) {return "DELETE";} else if (sqlStmt instanceof Drop) {return "DROP";} else if (sqlStmt instanceof Execute) {return "EXECUTE";} else if (sqlStmt instanceof Insert) {return "INSERT";} else if (sqlStmt instanceof Merge) {return "MERGE";} else if (sqlStmt instanceof Replace) {return "REPLACE";} else if (sqlStmt instanceof Select) {return "SELECT";} else if (sqlStmt instanceof Truncate) {return "TRUNCATE";} else if (sqlStmt instanceof Update) {return "UPDATE";} else if (sqlStmt instanceof Upsert) {return "UPSERT";} else {return "NONE";}}/*** 获取sql操作接口,与上面类型判断结合使用* example:* String sql = "create table a(a string)";* SqlType sqlType = SqlParserTool.getSqlType(sql);* if(sqlType.equals(SqlType.SELECT)){* Select statement = (Select) SqlParserTool.getStatement(sql);* }** @param sql* @return* @throws JSQLParserException*/public static Statement getStatement(String sql) throws JSQLParserException {Statement sqlStmt = CCJSqlParserUtil.parse(new StringReader(sql));return sqlStmt;}/*** 获取tables的表名** @param statement* @return*/public static <T> List<String> getTableList(T statement) {TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();List<String> tableList = tablesNamesFinder.getTableList((Statement) statement);return tableList;}/*** 获取join层级** @param selectBody* @return*/public static List<Join> getJoins(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {List<Join> joins = ((PlainSelect) selectBody).getJoins();return joins;}return new ArrayList<Join>();}/*** @param selectBody* @return*/public static List<Table> getIntoTables(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {List<Table> tables = ((PlainSelect) selectBody).getIntoTables();return tables;}return new ArrayList<Table>();}/*** @param selectBody* @return*/public static void setIntoTables(SelectBody selectBody, List<Table> tables) {if (selectBody instanceof PlainSelect) {((PlainSelect) selectBody).setIntoTables(tables);}}/*** 获取limit值** @param selectBody* @return*/public static Limit getLimit(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {Limit limit = ((PlainSelect) selectBody).getLimit();return limit;}return null;}/*** 为SQL增加limit值** @param selectBody* @param l*/public static void setLimit(SelectBody selectBody, long l) {if (selectBody instanceof PlainSelect) {Limit limit = new Limit();limit.setRowCount(new LongValue(String.valueOf(l)));((PlainSelect) selectBody).setLimit(limit);}}/*** 获取FromItem不支持子查询操作** @param selectBody* @return*/public static FromItem getFromItem(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {FromItem fromItem = ((PlainSelect) selectBody).getFromItem();return fromItem;} else if (selectBody instanceof WithItem) {getFromItem(selectBody);}return null;}/*** 获取子查询** @param selectBody* @return*/public static SubSelect getSubSelect(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {FromItem fromItem = ((PlainSelect) selectBody).getFromItem();if (fromItem instanceof SubSelect) {return ((SubSelect) fromItem);}} else if (selectBody instanceof WithItem) {getSubSelect(selectBody);}return null;}/*** 判断是否为多级子查询** @param selectBody* @return*/public static boolean isMultiSubSelect(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {FromItem fromItem = ((PlainSelect) selectBody).getFromItem();if (fromItem instanceof SubSelect) {SelectBody subBody = ((SubSelect) fromItem).getSelectBody();if (subBody instanceof PlainSelect) {FromItem subFromItem = ((PlainSelect) subBody).getFromItem();if (subFromItem instanceof SubSelect) {return true;}}}}return false;}/*** 获取查询字段** @param selectBody* @return*/public static List<SelectItem> getSelectItems(SelectBody selectBody) {if (selectBody instanceof PlainSelect) {List<SelectItem> selectItems = ((PlainSelect) selectBody).getSelectItems();return selectItems;}return null;}public static void main(String[] args) throws JSQLParserException {String sql = "SELECT table_name FROM information_schema.tables  WHERE table_name  like concat('edge_cs_user','%')";Statement statement = getStatement(sql);List<String> tableList = getTableList(statement);String sqlType = getSqlType(sql);System.out.println(sqlType);for (String s : tableList) {System.out.println(s);}}}
ShardingAlgorithmTool工具类,为了可以指定数据库创建指定分表操作,并将创建好的数据表缓存起来,下次就不用再重复创建
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.StrUtil;
import com.youxin.commons.commonsdata.service.EdgeOrgData;
import com.youxin.edge_service.ifoodapi.utils.IfoodApiUtils;
import lombok.extern.slf4j.Slf4j;import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;@Slf4j
public class ShardingAlgorithmTool {private static final HashSet<String> tableNameCache = new HashSet<>();/*** 判断 分表获取的表名是否存在 不存在则自动建表** @param logicTableName  逻辑表名(表头)* @param resultTableName 真实表名* @return 确认存在于数据库中的真实表名*/public static String shardingTablesCheckAndCreatAndReturn(String logicTableName, String resultTableName) {log.error(String.valueOf(EdgeOrgData.orgListMap));synchronized (logicTableName.intern()) {// 缓存中有此表 返回if (tableNameCache.contains(resultTableName)) {return resultTableName;}// 缓存中无此表 建表 并添加缓存List<String> sqlList = TablesNamesConfig.selectTableCreateSql(logicTableName);for (int i = 0; i < sqlList.size(); i++) {sqlList.set(i, sqlList.get(i).replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS").replace(logicTableName, resultTableName));}if (executeSql(sqlList)){tableNameCache.add(resultTableName);}}return resultTableName;}/*** 缓存重载方法*/public static void tableNameCacheReload(String active) {// 读取数据库中所有表名List<String> tableNameList = getAllTableNameBySchema(active);// 删除旧的缓存(如果存在)ShardingAlgorithmTool.tableNameCache.clear();// 写入新的缓存ShardingAlgorithmTool.tableNameCache.addAll(tableNameList);}private static boolean executeSql(List<String> sqlList) {final ClassPathResource resource = new ClassPathResource("application.yml");Properties properties = new Properties();try {properties.load(resource.getStream());String active = properties.getProperty("active");String propertiesname = "application.properties";switch (active) {case "dev":propertiesname = "application-dev.properties";break;case "test":propertiesname = "application-test.properties";break;case "prod":propertiesname = "application-prod.properties";break;default:break;}final ClassPathResource resource1 = new ClassPathResource(propertiesname);properties.load(resource1.getStream());} catch (IOException e) {log.error("读取sharding.yaml文件失败{}",e);return false;}try (Connection conn1 = DriverManager.getConnection(properties.getProperty("spring.shardingsphere.datasource.ds1.jdbc-url"),properties.getProperty("spring.shardingsphere.datasource.ds1.username"),properties.getProperty("spring.shardingsphere.datasource.ds1.password"))) {try (Statement st = conn1.createStatement()) {conn1.setAutoCommit(false);for (String sql : sqlList) {st.execute(sql);}conn1.commit();} catch (Exception ex) {log.error("执行sql失败,原因:{}", ex);conn1.rollback();return false;}} catch (Exception ex) {log.error("手动链接失败失败,原因:{}", ex);return false;}return true;}public static List<String> getAllTableNameBySchema(String active) {String propertiesname = "application.properties";switch (active) {case "dev":propertiesname = "application-dev.properties";break;case "test":propertiesname = "application-test.properties";break;case "prod":propertiesname = "application-prod.properties";break;default:break;}List<String> res = new ArrayList<>();final ClassPathResource resource = new ClassPathResource(propertiesname);Properties properties = new Properties();try {properties.load(resource.getStream());} catch (IOException e) {log.error("读取sharding.yaml文件失败");throw new RuntimeException(e);}String[] tablesNames = TablesNamesConfig.TABLES_NAMES.split(StrUtil.COMMA);for (String table_name : tablesNames) {String sql = "SELECT table_name FROM information_schema.tables  WHERE table_name  like concat(" + "'" + table_name + "'" + ",'%')";try (Connection connection = DriverManager.getConnection(properties.getProperty("spring.shardingsphere.datasource.ds1.jdbc-url"),properties.getProperty("spring.shardingsphere.datasource.ds1.username"),properties.getProperty("spring.shardingsphere.datasource.ds1.password"));Statement st = connection.createStatement()) {try (ResultSet rs = st.executeQuery(sql)) {while (rs.next()) {res.add(rs.getString(1));}}} catch (Exception e) {e.printStackTrace();}}return res;}public static HashSet<String> cacheTableNames() {return tableNameCache;}
}
DynamicTableConfig初始化

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
import org.apache.shardingsphere.api.config.sharding.strategy.HintShardingStrategyConfiguration;
import org.apache.shardingsphere.core.rule.ShardingDataSourceNames;
import org.apache.shardingsphere.core.rule.ShardingRule;
import org.apache.shardingsphere.core.rule.TableRule;
import org.apache.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.*;
import java.util.*;/*** 初始化动态分表信息** @author menshaojing*/
@Component
@Slf4j
public class DynamicTableConfig implements EnvironmentAware {/*** 数据库集合key**/private final static String DBS_KEY = "spring.shardingsphere.datasource.names";/*** 自定义水平分表集合key**/private final static String TABLES_KEY = "shardingsphere.sharding.tables";private final static String DATASOURCE_KEY = "spring.shardingsphere.datasource";/*** 数据库集合**/private String dbs;/*** 动态分表集合**/private String tables;private String driverClassName;private String jdbcUrl;private String userName;private String password;private Connection connection;@Resource(name = "shardingDataSource")private DataSource dataSource;/*** 初始化动态分表信息* ds0.edge_cs_user_org_id*/@PostConstructpublic void initDynamicTable() throws SQLException, ClassNotFoundException {log.info("动态初始化添加分库分表策略.....");ShardingDataSource dataSource = (ShardingDataSource) this.dataSource;ShardingRule tableRule = dataSource.getRuntimeContext().getRule();final Collection<TableRule> tableRules = tableRule.getTableRules();final List<String> tableList = Arrays.asList(this.tables.split(StrUtil.COMMA));//进行添加实际数据节点,hit分片for (String table : tableList) {log.info("开始动态初始化添加[{}]分表策略", table);addDefaultHitAlgorithm(table, tableRules);log.info("结束动态初始化添加[{}]分表策略", table);}}public void loadDatabase() throws ClassNotFoundException, SQLException {Class.forName(this.driverClassName);connection = DriverManager.getConnection(this.jdbcUrl, this.userName, this.password);}/*** 添加实际数据节点:按照组织id进行水平分表** @param table*/public String addDefaultActualDataNodes(String table) throws SQLException, ClassNotFoundException {loadDatabase();List<String> allOrg = getAllOrg();connection.close();StringBuilder stringBuilder = new StringBuilder();for (String db : this.dbs.split(StrUtil.COMMA)) {for (String org_id : allOrg) {stringBuilder.append(db).append(StrUtil.DOT).append(table).append(StrUtil.UNDERLINE).append(org_id.replaceAll("-", "")).append(StrUtil.COMMA);}}log.info("添加实际数据节点[{}] :{}", table, stringBuilder.substring(0, stringBuilder.length() - 1));return stringBuilder.substring(0, stringBuilder.length() - 1);}/*** 添加默认hit算法 algorithm** @param table* @param tableRules*/public void addDefaultHitAlgorithm(String table, Collection<TableRule> tableRules) throws SQLException, ClassNotFoundException {//表规则配置TableRuleConfiguration tableRuleConfiguration = new TableRuleConfiguration(table, addDefaultActualDataNodes(table));//添加默认数据库hit算法HintShardingStrategyConfiguration hintShardingStrategyConfiguration = new HintShardingStrategyConfiguration(new OrgAutoShardingSphereFixture());tableRuleConfiguration.setDatabaseShardingStrategyConfig(hintShardingStrategyConfiguration);log.info("添加默认数据库hit算法[{}]策略:{}", table, hintShardingStrategyConfiguration);//添加默认分表hit算法hintShardingStrategyConfiguration = new HintShardingStrategyConfiguration(new OrgAutoShardingSphereFixture());tableRuleConfiguration.setTableShardingStrategyConfig(hintShardingStrategyConfiguration);log.info("添加默认分表hit算法[{}]策略:{}", table, hintShardingStrategyConfiguration);//原始数据源集合Collection<String> rawDataSourceNames = new ArrayList<>();for (String db : this.dbs.split(StrUtil.COMMA)) {rawDataSourceNames.add(db);}ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration();ShardingDataSourceNames shardingDataSourceNames = new ShardingDataSourceNames(shardingRuleConfiguration, rawDataSourceNames);TableRule tableRule = new TableRule(tableRuleConfiguration, shardingDataSourceNames, null);tableRules.add(tableRule);}/*** 获取所有组织信息** @return*/private List<String> getAllOrg() throws SQLException {List<String> list = new ArrayList<>();final PreparedStatement preparedStatement = connection.prepareStatement("SELECT org_id from edge_org where activity != -1");final ResultSet resultSet = preparedStatement.executeQuery();while (resultSet.next()) {String org_id = resultSet.getObject(1, String.class);list.add(org_id);}preparedStatement.close();resultSet.close();return list;}@Overridepublic void setEnvironment(Environment environment) {this.dbs = environment.getProperty(DBS_KEY);this.tables = TablesNamesConfig.TABLES_NAMES;String db = this.dbs.split(StrUtil.COMMA)[0];final String s = DATASOURCE_KEY + StrUtil.DOT + db + StrUtil.DOT + "driver-class-name";this.driverClassName = environment.getProperty(DATASOURCE_KEY + StrUtil.DOT + db + StrUtil.DOT + "driver-class-name");this.jdbcUrl = environment.getProperty(DATASOURCE_KEY + StrUtil.DOT + db + StrUtil.DOT + "jdbc-url");this.userName = environment.getProperty(DATASOURCE_KEY + StrUtil.DOT + db + StrUtil.DOT + "username");this.password = environment.getProperty(DATASOURCE_KEY + StrUtil.DOT + db + StrUtil.DOT + "password");}}
OrgAutoShardingSphereFixture类,实现Hint分片,这里是最主要的业务核心
import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.hint.HintShardingValue;
import org.springframework.stereotype.Component;import java.util.*;
import java.util.stream.Collectors;/*** 自定义分片算法,继承实现Hint分片** @Created by xieyaoyi* @Created_date 2023/12/1*/
@Slf4j
@Component
public class OrgAutoShardingSphereFixture implements HintShardingAlgorithm<String> {/*** @param collection        数据源集合*                          在分库时值为所有分片库的集合 databaseNames*                          分表时为对应分片库中所有分片表的集合 tablesNames* @param hintShardingValue 分片属性,包括*                          logicTableName 为逻辑表,*                          columnName 分片健(字段),hit策略此处为空 ""*                          <p>*                          value 【之前】都是 从 SQL 中解析出的分片健的值,用于取模判断*                          HintShardingAlgorithm不再从SQL 解析中获取值,而是直接通过*                          hintManager.addTableShardingValue("edge_cs_user", “003538e36799cec47ebbe1d56fa1671bde9”)参数进行指定* @return*/@Overridepublic Collection<String> doSharding(Collection<String> collection, HintShardingValue<String> hintShardingValue) {//collection.forEach(i -> System.out.println("节点配置表名为: " + i));Collection<String> result = new ArrayList<>();Set<String> tableSet = collection.stream().collect(Collectors.toSet());for (String shardingValue : hintShardingValue.getValues()) {String value = hintShardingValue.getLogicTableName() + "_" + shardingValue;if (!tableSet.isEmpty() && tableSet.contains(value)) {ShardingAlgorithmTool.shardingTablesCheckAndCreatAndReturn(hintShardingValue.getLogicTableName(), value);result.add(value);}else {ShardingAlgorithmTool.shardingTablesCheckAndCreatAndReturn(hintShardingValue.getLogicTableName(), value);result.add(value);}}return result;}}
ShardingTablesLoadRunner类
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** 项目启动后 读取已有分表 进行缓存*/
@Slf4j
@Order
@Component
public class ShardingTablesLoadRunner implements CommandLineRunner {@Value("${spring.profiles.active:prod}")private String active;@Overridepublic void run(String... args) {ShardingAlgorithmTool.tableNameCacheReload(active);}
}
EdgeUserAndOrderServiceInterceptor类,做sql拦截,用于sql进行分表创建和查询
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.youxin.shardingsphere.SqlParserHandler;
import com.youxin.shardingsphere.TablesNamesConfig;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.statement.Statement;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.shardingsphere.api.hint.HintManager;
import org.springframework.stereotype.Component;import java.sql.SQLException;
import java.util.List;/*** 用户表、订单表分表** @Created by xieyaoyi* @Created_date 2023/12/4*/
@Component
@Slf4j
public class EdgeUserAndOrderServiceInterceptor implements InnerInterceptor {/*** 判断是否符合规则** @param sql* @return*/public boolean judgmentSql(String sql) {String[] tableames = TablesNamesConfig.TABLES_NAMES.split(StrUtil.COMMA);for (String table_name : tableames) {if (sql.toLowerCase().indexOf("from " + table_name) > 0|| sql.toLowerCase().indexOf("update " + table_name) >= 0|| sql.toLowerCase().indexOf("into " + table_name) > 0) {return true;}}return false;}@Overridepublic void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {BoundSql boundSql = ms.getBoundSql(parameter);String sql = boundSql.getSql();if (!judgmentSql(sql)) {return;}String state = JSONObject.parseObject(JSON.toJSON(parameter).toString()).getString("state");if (parameter != null && StringUtils.isNotBlank(state)) {try {Statement statement = SqlParserHandler.getStatement(sql);final List<String> tableList = SqlParserHandler.getTableList(statement);//清除历史规则HintManager.clear();//获取对应的实例HintManager hintManager = HintManager.getInstance();for (String table : tableList) {//设置表的分片键值,value是用于表分片hintManager.addTableShardingValue(table, state);}log.info("解析SQL表名:{}", tableList);} catch (JSQLParserException e) {log.error("解析SQL表名失败:{}", e);throw new RuntimeException(e);}}}@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {boundSql = ms.getBoundSql(parameter);String sql = boundSql.getSql();if (!judgmentSql(sql)) {return;}String state = JSONObject.parseObject(JSON.toJSON(parameter).toString()).getString("state");if (parameter != null && StringUtils.isNotBlank(state)) {try {Statement statement = SqlParserHandler.getStatement(sql);final List<String> tableList = SqlParserHandler.getTableList(statement);//清除历史规则HintManager.clear();//获取对应的实例HintManager hintManager = HintManager.getInstance();for (String table : tableList) {//设置表的分片键值,value是用于表分片hintManager.addTableShardingValue(table, state);}log.info("解析SQL表名:{}", tableList);} catch (JSQLParserException e) {log.error("解析SQL表名失败:{}", e);throw new RuntimeException(e);}}}
}
MybatisPlusConfig做拦截器扫描配置进来
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.youxin.commons.interceptor.service.EdgeUserAndOrderServiceInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Created by xieyaoyi* @Created_date 2023/12/4*/
@Slf4j
@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();addPaginationInnerInterceptor(interceptor);return interceptor;}private void addPaginationInnerInterceptor(MybatisPlusInterceptor interceptor) {//分页interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));//动态表拦截器interceptor.addInnerInterceptor(new EdgeUserAndOrderServiceInterceptor());}}

以上就是主要的分表业务代码了,但是注意的是以上只是显示了基本的框架,你在插入或者查询的时候,是需要带上分表关键字段的数据,才能做到真正的切换指定的表数据

如:我这里是使用state这个字段作为分表的关键字段,所以在插入、查询、更新。或者删除的时候都必须传入这个参数,及时我的mapper里面不需要这个参数的使用

示例:

    public EdgeOrderInfo getEdgeOrderInfo(String order_no, String state) {return edgeOrderMapper.getOrderInfoByOrderNo(order_no, state);}public EdgeOrderInfo addOrUpdateEdgeOrderInfo(EdgeOrderInfo orderInfo) {if (StringUtils.isBlank(orderInfo.getOrder_no())) {orderInfo.setOrder_no(CreateNoUtils.getCreateOrderNo(6));}if (StringUtils.isBlank(orderInfo.getState())) {orderInfo.setState(orderInfo.getOrg_id().replaceAll("-", ""));}if (getEdgeOrderInfo(orderInfo.getOrder_no(), orderInfo.getState()) != null) {orderInfo.setUpdated_date(new Date());edgeOrderMapper.updateByOrderNo(orderInfo, orderInfo.getState());} else {edgeOrderMapper.insert(orderInfo);}return orderInfo;}

这样在sql拦截后,就会经过OrgAutoShardingSphereFixture类将edge_order_info替换edge_order_info_${uuid}了

数据库效果展示:

我也是参考别人的博客写的,推荐一下写得可以的博客一起学习一下

参考博客:

https://blog.csdn.net/weixin_39403349/article/details/130264892

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

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

相关文章

软件测试|Django 入门:构建Python Web应用的全面指南

引言 Django 是一个强大的Python Web框架&#xff0c;它以快速开发和高度可扩展性而闻名。本文将带您深入了解Django的基本概念和核心功能&#xff0c;帮助您从零开始构建一个简单的Web应用。 什么是Django&#xff1f; Django 是一个基于MVC&#xff08;模型-视图-控制器&a…

A preview error may have occurred. Switch to the Log tab to view details.

记录一下当时刚开始学习鸿蒙开发犯的错误 UIAbility内页面间的跳转内容的时候会遇到页面无法跳转的问题 并伴随标题错误 我们跳转页面需要进行注册 路由表路径&#xff1a; entry > src > main > resources > base > profile > main_pages.json 或者是页面…

鸿鹄电子招投标系统:企业战略布局下的采购寻源解决方案

在数字化采购领域&#xff0c;企业需要一个高效、透明和规范的管理系统。通过采用Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;我们打造了全过程数字化采购管理平台。该平台具备内外协同的能力&#xff0c;通过待办消息、招标公告、中标公告和信息发布等功能模块…

面试宝典进阶之Java线程面试题

T1、【初级】线程和进程有什么区别&#xff1f; &#xff08;1&#xff09;线程是CPU调度的最小单位&#xff0c;进程是计算分配资源的最小单位。 &#xff08;2&#xff09;一个进程至少要有一个线程。 &#xff08;3&#xff09;进程之间的内存是隔离的&#xff0c;而同一个…

Untiy HTC Vive VRTK 开发记录

目录 一.概述 二.功能实现 1.模型抓取 1&#xff09;基础抓取脚本 2&#xff09;抓取物体在手柄上的角度 2.模型放置区域高亮并吸附 1&#xff09;VRTK_SnapDropZone 2&#xff09;VRTK_PolicyList 3&#xff09;VRTK_SnapDropZone_UnityEvents 3.交互滑动条 4.交互旋…

coredump+gdb调试

1、什么是coredump Coredump&#xff08;核心转储&#xff09;是操作系统在程序异常终止&#xff08;例如由于段错误或其他严重错误&#xff09;时创建的一种文件。这个文件包含了程序崩溃时刻进程的内存镜像&#xff0c;通常还包括程序计数器、寄存器内容和堆栈内存等信息&am…

CH09_避免浪费

Flyweight模式 享元模式&#xff08;Flyweight&#xff09;&#xff0c;运用共享技术有效地支持大量细粒度的对象。 类图 说明 Flyweight&#xff08;轻量级&#xff09; 按照通常方式编写程序会导致程序变重&#xff0c;所以如果能够共享实例会比较好&#xff0c;而Flyweigh…

idea右上角浏览器图标没有idea内部浏览器怎么显示

idea右上角浏览器图标没有idea内部浏览器怎么显示 file -> settings -> tools -> web brosers 选择需要的浏览器&#xff0c;勾选上展示到编辑器中 打开上图的Built-in Preview&#xff0c;就会显示idea标志的内部显示了&#xff01;&#xff01;&#xff01;

UWB 技术及应用

超宽带技术为工业自动化提供独特优势&#xff0c;是首要的室内定位技术。 UWB 因其相对于 RFID、BLE 或 WiFi 等同类技术的众多优势而被认为是室内定位技术的黄金标准。它是基于位置的自动化的理想解决方案。 UWB 结合了短光速脉冲&#xff0c;可在宽带宽上精确测量信号到达时…

错误0x80070091(目录不是空的) 解决方案

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读问题产生&#xff1a;解决方案&#xff1a;方法一&#xff1a;方法二&#x…

Linux下进程控制

文章目录 创建进程fork创建进程fork返回值写诗拷贝fork常规用法fork失败的原因 进程终止进程正常终止查看进程退出码_exit函数exit函数exit 和 _exit 的区别return退出 进程等待进程等待的方式wait方法(系统调用)waitpid方法(系统调用) WEXITSTATUS 和 WIFEXITED阻塞等待和非阻…

Windows 安装Hyber-V,并创建虚拟机

文章目录 Hyper-V名词解释Hyper-V 有哪些功能&#xff1f;Windows 上怎么启用Hyber-V1&#xff0c;通过“设置”启用 Hyper-V 角色2&#xff0c;使用 PowerShell 启用 Hyper-V3&#xff0c;使用 CMD 和 DISM 启用 Hyper-V 利用Hyper-V创建一个虚拟机 Hyper-V名词解释 Hyper-V …

科研绘图(一)山脊图

从今日开始&#xff0c;为大家开辟一个新的系列科研绘图。同一个竞赛下&#xff0c;大家都近乎相同的解题思路下。之所以能出现一等二等三等奖的区别很大部分都在于结果的可视化&#xff0c;为了能更好地帮助大家进行可视化&#xff0c;今后将专门推出一个可视化板块&#xff0…

解决方案|镭速助力汽车行业实现数据高速传输数字化进程

在新一代信息技术驱动的数字经济时代&#xff0c;数据已然成为新型生产要素&#xff0c;是国家基础性资源和战略性资源&#xff0c;在汽车市场全球化背景下&#xff0c;产品、数据跨境、区域协同将成为车企未来常态。 1、数字时代&#xff0c;车企数据管理面临新课题 汽车产业…

使用Nonebot编写QQ机器人

使用 NoneBot 这个工具&#xff0c;来编写 QQ 机器人。 安装基础软件 一、安装 NoneBot 库 直接使用 pip 安装即可 pip install nonebot二、安装酷Q 软件和 HTTP API 插件 酷Q 软件可以直接到官网下载&#xff0c;https://cqp.cc/b/news&#xff0c;或者可以到网盘下载&am…

互斥、自旋、读写锁的应用场景

互斥、自旋、读写锁的应用场景 锁&#x1f512;1、互斥锁、自旋锁2、读写锁&#xff1a;读写的优先级3、乐观锁和悲观锁总结&#xff1a; 锁&#x1f512; ​ 多线程访问共享资源的生活&#xff0c;避免不了资源竞争而导致错乱的问题&#xff0c;所以我们通常为了解决这一问题…

虚拟机Ubuntu网络配置

电脑有两个系统&#xff0c;windows系统和ubuntu系统&#xff0c;那网卡到底给哪一个用呢&#xff0c;所以要选择桥接模式&#xff0c;就可以共用网卡 但是我们电脑网卡&#xff0c;有线网卡&#xff0c;无线网卡&#xff0c;到底使用哪个网卡&#xff0c;所以选择桥接到自动或…

Word中的书签

书签是一种标记&#xff0c;用于标记文档中的特定位置&#xff0c;以便稍后快速导航到该位置。 我常用的是WPS里面的Word 1、如何使用书签 书签在插入选项卡下可以找到。 点击书签后&#xff0c;设置好书签名称&#xff0c;添加即可。 接下来在视图选项卡中找到导航窗口。选…

docker搭建部署mysql并挂载指定目录

Docker是一种轻量级、可移植的容器化平台&#xff0c;可以简化应用程序的部署和管理。在本文中&#xff0c;我们将探讨如何使用Docker来搭建和部署MySQL数据库&#xff0c;并将数据和配置文件挂载到外部目录&#xff0c;以实现数据持久化和方便的配置管理。 1: 安装Docker 首…

基于蚁群算法的TSP问题建模求解(Python)

基于蚁群算法的TSP问题建模求解 一、蚁群优化算法&#xff08;Ant Colony Optimization&#xff0c;ACO&#xff09;1.1 蚁群算法的起源——“双桥实验”1.2 蚁群优化算法思想1.3 蚁群算法应用于求解组合优化问题 二、基于蚁群算法的TSP问题建模求解2.1 旅行商问题&#xff08;…