领导:数据太多了,你按照接入方给我把xx表给我分表下! 以前的代码不准改哈

62 阅读3分钟

领导:数据太多了,你按照接入方给我把xx表给我分表下! 以前的代码不准改哈

今天领导让我做数据分表。。。数据的确有点多哈(多吗?8百万条?不多吧,不过以后接入方多了,估计会很多吧)

然后随便看了下 sharding、mycat..

emmmm 我是按照具体字段去分割,不需要太复杂,如果表不存在 报错就行,没有太多复杂的东西,所以。。。

自己写一个吧

领导需求列出来了

  1. 你得能按照某个字段分表
  2. 你不能改代码

不能改代码?还得分表?!!!

开始分析框架:用的Mybatis-plus

哦~ 可以搞!!!

用到一个玩意:DynamicTableNameInnerInterceptor

不知道有人会不会用到这个,如果用到的 可以评论 ,有时间我回回复,所以。。。 我就贴一下主要代码

至于哪个地方用这个 Interceptor emmmm 评论区问我下

@Slf4j
@Component("customerDynamicTableNameInnerInterceptor")
public class CustomerDynamicTableNameInnerInterceptor extends DynamicTableNameInnerInterceptor {

    private final Map<String, TableNameHandler> tableNameHandlerMap = new ConcurrentHashMap<>();

    private final Map<String, String> tableNameMap = new ConcurrentHashMap<String, String>() {
        {
            put("xxxx", "xxxx");
            put("xxxxxxx", "xxxxxx");
            put("xxxxxxxx", "xxxx");
            put("xxxxxxxxxx", "xxxxx");
        }
    };


    private String customerChangeTable(String sql, SqlCommandType type, List<ParameterMapping> parameterMappings, Object parameterObject) {
        TableNameParser parser = new TableNameParser(sql);
        List<TableNameParser.SqlToken> names = new ArrayList<>();
        parser.accept(names::add);
        StringBuilder builder = new StringBuilder();
        int last = 0;
        for (TableNameParser.SqlToken name : names) {
            int start = name.getStart();
            if (start != last) {
                builder.append(sql, last, start);
                String value = name.getValue();
                TableNameHandler handler = tableNameHandlerMap.get(value);
                if (handler != null) {
                    builder.append(handler.dynamicTableName(sql, value));
                } else {
                    // 此处判断是否 需要修改 table名称
                    if (tableNameMap.containsKey(value)) {
                        builder.append(tableNameHandler(sql, value, type, parameterMappings, parameterObject));
                    } else {
                        builder.append(value);
                    }
                }
            }
            last = name.getEnd();
        }
        if (last != sql.length()) {
            builder.append(sql.substring(last));
        }
        return builder.toString();
    }

    private final ObjectFactory objectFactory = new DefaultObjectFactory();
    private final ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
    private final ReflectorFactory reflectorFactory = new DefaultReflectorFactory();

    private String tableNameHandler(String sql, String tableName, SqlCommandType type, List<ParameterMapping> parameterMappings, Object parameterObject) {
        String tableFiled = tableNameMap.get(tableName);
        int index = sql.indexOf(tableFiled);
        if (index == -1) {
            return tableName;
        }
        if (type == SqlCommandType.SELECT || type == SqlCommandType.UPDATE || type == SqlCommandType.DELETE) {
            index = sql.indexOf(tableFiled + " = ?");
            if (index == -1) return tableName;
            // 1. 获取当前 这个index 是多少个问号呀
            int position = getPlaceholderPosition(sql, index + ((tableFiled + " = ?").length()) - 1, "?");
            return getTableName(tableName, position, parameterMappings, parameterObject);
        } else if (type == SqlCommandType.INSERT) {
            // 查询出当前 对应的 index 是哪一个
            int position = getInsertPosition(getParts(sql), tableFiled);
            return getTableName(tableName, position, parameterMappings, parameterObject);
        }
        return tableName;
    }

    private String getTableName(String tableName, int position, List<ParameterMapping> parameterMappings, Object parameterObject) {
        if (position <= 0) {
            return tableName;
        }
        ParameterMapping parameterMapping = parameterMappings.get(position - 1);
        String property = parameterMapping.getProperty();
        // 从 parameterObject中获取
        MetaObject metaObject = MetaObject.forObject(parameterObject, objectFactory, objectWrapperFactory, reflectorFactory);
        Object value = metaObject.getValue(property);
        return tableName + "_" + value;
    }

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
        if (InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) return;
        mpBs.sql(this.customerChangeTable(mpBs.sql(), SqlCommandType.SELECT, mpBs.parameterMappings(), mpBs.parameterObject()));
    }

    @Override
    public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {
        PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);
        MappedStatement ms = mpSh.mappedStatement();
        SqlCommandType sct = ms.getSqlCommandType();
        if (sct == SqlCommandType.INSERT || sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) {
            if (InterceptorIgnoreHelper.willIgnoreDynamicTableName(ms.getId())) return;
            PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
            mpBs.sql(this.customerChangeTable(mpBs.sql(), sct, mpBs.parameterMappings(), mpBs.parameterObject()));
        }
    }


    /**
     * 找到SQL语句中所有?的下标
     *
     * @param sql SQL语句
     * @return 包含所有?下标的列表
     */
    public static List<Integer> findPlaceholderIndexes(String sql, String placeholder) {
        List<Integer> indexes = new ArrayList<>();
        int index = 0;
        while ((index = sql.indexOf(placeholder, index)) != -1) {
            indexes.add(index);
            index++; // 移动到下一个字符,避免重复计算
        }
        return indexes;
    }

    /**
     * 判断给定的下标是第几个?占位符
     *
     * @param sql         SQL语句
     * @param givenIndex  给定的下标
     * @param placeholder 占位符
     * @return 给定下标是第几个?占位符,如果不存在则返回-1
     */
    public static int getPlaceholderPosition(String sql, int givenIndex, String placeholder) {
        List<Integer> indexes = findPlaceholderIndexes(sql, placeholder);
        for (int i = 0; i < indexes.size(); i++) {
            if (indexes.get(i) == givenIndex) {
                return i + 1; // 返回的是第几个占位符,所以加1
            }
        }
        return -1; // 如果给定的下标不在列表中,返回-1
    }


    /**
     * 找到SQL语句中所有?的下标
     *
     * @param sql SQL语句
     * @return 包含所有?下标的列表
     */
    public static List<Integer> findPlaceholderIndexes(String sql) {
        List<Integer> indexes = new ArrayList<>();
        int index = 0;
        while ((index = sql.indexOf('?', index)) != -1) {
            indexes.add(index);
            index++; // 移动到下一个字符,避免重复计算
        }
        return indexes;
    }

    /**
     * 根据列名找到对应的?占位符的下标
     *
     * @param sql        SQL语句
     * @param columnName 列名
     * @return ?占位符的下标,如果未找到则返回-1
     */
    public static int findPlaceholderIndexByColumn(String sql, String columnName) {
        String[] parts = sql.split("\\s*,\\s*");
        for (int i = 0; i < parts.length; i++) {
            if (parts[i].trim().contains(columnName)) {
                List<Integer> indexes = findPlaceholderIndexes(sql);
                if (i < indexes.size()) {
                    return indexes.get(i);
                }
                break;
            }
        }
        return -1;
    }

    public static List<String> getParts(String sql) {
        int i = sql.toLowerCase().indexOf("value");
        String s1 = sql.substring(0, i);
        String[] split = s1.split("\\s*,\\s*");
        List<String> returnList = new ArrayList<>(Arrays.asList(split));
        String s2 = sql.substring(i);
        boolean flag = false;
        int startIndex = 0;
        for (int index = 0; index < s2.toCharArray().length; index++) {
            char c = s2.charAt(index);
            if (c == '\'') {
                flag = !flag;
            }
            if (!flag) {
                if (c == ',' || c == ')') {
                    returnList.add(s2.substring(startIndex, index));
                    startIndex = index + 1;
                }
            }
        }
        return returnList;
    }

    public static int getInsertPosition(List<String> parts, String tableFiled) {
        String placeholder = "?";
        int positionIndex = -1;
        int startIndex = 0;
        int placeholderIndex = 0;
        int returnIndex = -1;
        boolean startFlag = false;
        for (int i = 0; i < parts.size(); i++) {
            String part = parts.get(i);
            if (part.contains(tableFiled)) {
                // index
                positionIndex = i + 1;
            }
            if (part.toLowerCase().contains("value")) {
                startFlag = true;
            }
            if (startFlag) {
                startIndex++;
            }
            if (part.contains(placeholder)) {
                placeholderIndex++;
            }
            if (startIndex == positionIndex) {
                returnIndex = placeholderIndex;
            }
        }
        return returnIndex;
    }

}

最后 祝大家在这个新年的钟声里,愿你的生活中充满欢笑,事业上收获满满,爱情里甜蜜温馨。新年快乐!