zhuml4
2026-03-05 d6b4a1373d51f53d2e68b589c03b91511ece0c83
fix:推单流程问题
6个文件已添加
1个文件已修改
1193 ■■■■■ 已修改文件
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/ShardingQueryHelper.java 289 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/ShardingTableUtil.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/test/java/com/xiaopeng/itinerary/utils/ShardingUtilExample.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/ShardingQueryHelper.java 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/ShardingTableUtil.java 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/test/java/com/xiaopeng/order/ShardingUtilExample.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/ShardingQueryHelper.java
New file
@@ -0,0 +1,289 @@
package com.xiaopeng.itinerary.utils;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
 * 分表查询辅助工具类
 * 提供分表查询的SQL构建和批量查询支持
 *
 * @author auto-generated
 */
@Slf4j
public class ShardingQueryHelper {
    /**
     * 构建单个分表的查询SQL
     *
     * @param baseTableName 基础表名
     * @param shardingValue 分片键值
     * @param shardingCount 分片数量
     * @param whereClause   WHERE子句(不包含WHERE关键字)
     * @return 完整的查询SQL
     */
    public static String buildSingleTableQuery(String baseTableName, Long shardingValue,
                                               int shardingCount, String whereClause) {
        String tableName = ShardingTableUtil.getShardingTableName(baseTableName, shardingValue, shardingCount);
        StringBuilder sql = new StringBuilder("SELECT * FROM ");
        sql.append(tableName);
        if (whereClause != null && !whereClause.trim().isEmpty()) {
            sql.append(" WHERE ").append(whereClause);
        }
        String query = sql.toString();
        log.debug("Generated single table query: {}", query);
        return query;
    }
    /**
     * 构建全表扫描的UNION查询SQL(适用于需要查询所有分表的场景)
     *
     * @param baseTableName 基础表名
     * @param shardingCount 分片数量
     * @param whereClause   WHERE子句(不包含WHERE关键字)
     * @param orderBy       排序字句(不包含ORDER BY关键字)
     * @param limit         限制返回数量,null表示不限制
     * @return UNION查询SQL
     */
    public static String buildUnionAllQuery(String baseTableName, int shardingCount,
                                           String whereClause, String orderBy, Integer limit) {
        StringBuilder sql = new StringBuilder();
        for (int i = 0; i < shardingCount; i++) {
            if (i > 0) {
                sql.append(" UNION ALL ");
            }
            sql.append("SELECT * FROM ").append(baseTableName).append("_").append(i);
            if (whereClause != null && !whereClause.trim().isEmpty()) {
                sql.append(" WHERE ").append(whereClause);
            }
        }
        // 外层排序和限制
        if (orderBy != null && !orderBy.trim().isEmpty()) {
            sql.insert(0, "SELECT * FROM (");
            sql.append(") AS union_result ORDER BY ").append(orderBy);
        }
        if (limit != null && limit > 0) {
            sql.append(" LIMIT ").append(limit);
        }
        String query = sql.toString();
        log.debug("Generated union all query for {} tables: {}", shardingCount, query);
        return query;
    }
    /**
     * 获取需要查询的分表索引列表(基于分片键值范围)
     *
     * @param startValue    起始分片键值
     * @param endValue      结束分片键值
     * @param shardingCount 分片数量
     * @return 需要查询的表索引列表
     */
    public static List<Integer> getShardingIndexesInRange(Long startValue, Long endValue, int shardingCount) {
        List<Integer> indexes = new ArrayList<>();
        if (startValue == null || endValue == null || startValue > endValue) {
            log.warn("Invalid range: start={}, end={}, returning all indexes", startValue, endValue);
            for (int i = 0; i < shardingCount; i++) {
                indexes.add(i);
            }
            return indexes;
        }
        // 计算涉及的分表索引
        for (long value = startValue; value <= endValue; value++) {
            int index = (int) (value % shardingCount);
            if (!indexes.contains(index)) {
                indexes.add(index);
            }
        }
        log.debug("Range query from {} to {} covers indexes: {}", startValue, endValue, indexes);
        return indexes;
    }
    /**
     * 构建基于索引列表的UNION查询
     *
     * @param baseTableName    基础表名
     * @param tableIndexes     要查询的表索引列表
     * @param whereClause      WHERE子句
     * @param orderBy          排序字句
     * @param limit            限制数量
     * @return UNION查询SQL
     */
    public static String buildUnionQueryByIndexes(String baseTableName, List<Integer> tableIndexes,
                                                  String whereClause, String orderBy, Integer limit) {
        if (tableIndexes == null || tableIndexes.isEmpty()) {
            log.warn("No table indexes provided, returning empty query");
            return "";
        }
        StringBuilder sql = new StringBuilder();
        for (int i = 0; i < tableIndexes.size(); i++) {
            if (i > 0) {
                sql.append(" UNION ALL ");
            }
            int tableIndex = tableIndexes.get(i);
            sql.append("SELECT * FROM ").append(baseTableName).append("_").append(tableIndex);
            if (whereClause != null && !whereClause.trim().isEmpty()) {
                sql.append(" WHERE ").append(whereClause);
            }
        }
        // 外层排序和限制
        if (orderBy != null && !orderBy.trim().isEmpty()) {
            sql.insert(0, "SELECT * FROM (");
            sql.append(") AS union_result ORDER BY ").append(orderBy);
        }
        if (limit != null && limit > 0) {
            sql.append(" LIMIT ").append(limit);
        }
        String query = sql.toString();
        log.debug("Generated union query for indexes {}: {}", tableIndexes, query);
        return query;
    }
    /**
     * 行程相关表的批量查询SQL构建器
     */
    public static class ItineraryQueryBuilder {
        /**
         * 根据用户ID查询操作日志
         */
        public static String querySysOperLogByUserId(Long userId, String additionalWhere) {
            String tableName = ShardingTableUtil.getSysOperLogTableName(userId);
            StringBuilder sql = new StringBuilder("SELECT * FROM ").append(tableName);
            sql.append(" WHERE userId = ").append(userId);
            if (additionalWhere != null && !additionalWhere.trim().isEmpty()) {
                sql.append(" AND ").append(additionalWhere);
            }
            return sql.toString();
        }
        /**
         * 根据用户ID查询协议用户信息
         */
        public static String queryAgreementAppUserByUserId(Long appUserId) {
            String tableName = ShardingTableUtil.getAgreementAppUserTableName(appUserId);
            return "SELECT * FROM " + tableName + " WHERE app_user_id = " + appUserId;
        }
        /**
         * 根据电子围栏区域ID查询点位信息
         */
        public static String queryPointByElectronicAreaId(Long electronicAreaId) {
            String tableName = ShardingTableUtil.getPointTableName(electronicAreaId);
            return "SELECT * FROM " + tableName + " WHERE electronic_area_id = " + electronicAreaId;
        }
        /**
         * 查询所有操作日志(全表扫描)
         */
        public static String queryAllSysOperLogs(String whereClause, String orderBy, Integer limit) {
            return ShardingQueryHelper.buildUnionAllQuery("sys_oper_log", 10, whereClause, orderBy, limit);
        }
        /**
         * 查询所有协议用户(全表扫描)
         */
        public static String queryAllAgreementAppUsers(String whereClause, String orderBy, Integer limit) {
            return ShardingQueryHelper.buildUnionAllQuery("xp_agreement_app_user", 10, whereClause, orderBy, limit);
        }
        /**
         * 查询所有点位(全表扫描)
         */
        public static String queryAllPoints(String whereClause, String orderBy, Integer limit) {
            return ShardingQueryHelper.buildUnionAllQuery("xp_point", 10, whereClause, orderBy, limit);
        }
    }
    /**
     * 分表查询计数工具
     */
    public static class ShardingCountHelper {
        /**
         * 构建分表计数查询(UNION ALL + SUM)
         */
        public static String buildCountQuery(String baseTableName, int shardingCount, String whereClause) {
            StringBuilder sql = new StringBuilder("SELECT SUM(cnt) AS total_count FROM (");
            for (int i = 0; i < shardingCount; i++) {
                if (i > 0) {
                    sql.append(" UNION ALL ");
                }
                sql.append("SELECT COUNT(*) AS cnt FROM ").append(baseTableName).append("_").append(i);
                if (whereClause != null && !whereClause.trim().isEmpty()) {
                    sql.append(" WHERE ").append(whereClause);
                }
            }
            sql.append(") AS count_result");
            String query = sql.toString();
            log.debug("Generated count query: {}", query);
            return query;
        }
        /**
         * 统计所有操作日志数量
         */
        public static String countAllSysOperLogs(String whereClause) {
            return buildCountQuery("sys_oper_log", 10, whereClause);
        }
        /**
         * 统计所有协议用户数量
         */
        public static String countAllAgreementAppUsers(String whereClause) {
            return buildCountQuery("xp_agreement_app_user", 10, whereClause);
        }
        /**
         * 统计所有点位数量
         */
        public static String countAllPoints(String whereClause) {
            return buildCountQuery("xp_point", 10, whereClause);
        }
    }
    /**
     * 打印查询示例
     */
    public static void printQueryExamples() {
        log.info("========== Sharding Query Examples ==========");
        log.info("1. Query sys_oper_log by userId 12345:");
        log.info("   {}", ItineraryQueryBuilder.querySysOperLogByUserId(12345L, "status = 1"));
        log.info("");
        log.info("2. Query agreement_app_user by userId 67890:");
        log.info("   {}", ItineraryQueryBuilder.queryAgreementAppUserByUserId(67890L));
        log.info("");
        log.info("3. Query all sys_oper_logs (UNION ALL):");
        log.info("   {}", ItineraryQueryBuilder.queryAllSysOperLogs("status = 1", "create_time DESC", 100));
        log.info("");
        log.info("4. Count all agreement_app_users:");
        log.info("   {}", ShardingCountHelper.countAllAgreementAppUsers(null));
        log.info("=============================================");
    }
}
xp-robotaxi-itinerary-boot/src/main/java/com/xiaopeng/itinerary/utils/ShardingTableUtil.java
New file
@@ -0,0 +1,149 @@
package com.xiaopeng.itinerary.utils;
import lombok.extern.slf4j.Slf4j;
/**
 * 分表工具类
 * 根据 ShardingSphere 配置计算实际的分表名称
 *
 * @author auto-generated
 */
@Slf4j
public class ShardingTableUtil {
    /**
     * 根据用户ID计算操作日志表的实际表名
     * 分片规则: sys_oper_log_${userId % 10}
     *
     * @param userId 用户ID
     * @return 实际表名,如: sys_oper_log_5
     */
    public static String getSysOperLogTableName(Long userId) {
        if (userId == null) {
            log.warn("userId is null, returning default table name");
            return "sys_oper_log_0";
        }
        int tableIndex = (int) (userId % 10);
        String tableName = "sys_oper_log_" + tableIndex;
        log.debug("userId: {}, calculated table name: {}", userId, tableName);
        return tableName;
    }
    /**
     * 根据用户ID计算协议用户表的实际表名
     * 分片规则: xp_agreement_app_user_${app_user_id % 10}
     *
     * @param appUserId 用户ID
     * @return 实际表名,如: xp_agreement_app_user_5
     */
    public static String getAgreementAppUserTableName(Long appUserId) {
        if (appUserId == null) {
            log.warn("appUserId is null, returning default table name");
            return "xp_agreement_app_user_0";
        }
        int tableIndex = (int) (appUserId % 10);
        String tableName = "xp_agreement_app_user_" + tableIndex;
        log.debug("appUserId: {}, calculated table name: {}", appUserId, tableName);
        return tableName;
    }
    /**
     * 根据电子围栏区域ID计算点位表的实际表名
     * 分片规则: xp_point_${electronic_area_id % 10}
     *
     * @param electronicAreaId 电子围栏区域ID
     * @return 实际表名,如: xp_point_5
     */
    public static String getPointTableName(Long electronicAreaId) {
        if (electronicAreaId == null) {
            log.warn("electronicAreaId is null, returning default table name");
            return "xp_point_0";
        }
        int tableIndex = (int) (electronicAreaId % 10);
        String tableName = "xp_point_" + tableIndex;
        log.debug("electronicAreaId: {}, calculated table name: {}", electronicAreaId, tableName);
        return tableName;
    }
    /**
     * 获取所有操作日志表名列表(用于全表扫描场景)
     *
     * @return 所有操作日志表名数组,共10个表
     */
    public static String[] getAllSysOperLogTableNames() {
        String[] tableNames = new String[10];
        for (int i = 0; i < 10; i++) {
            tableNames[i] = "sys_oper_log_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有协议用户表名列表(用于全表扫描场景)
     *
     * @return 所有协议用户表名数组,共10个表
     */
    public static String[] getAllAgreementAppUserTableNames() {
        String[] tableNames = new String[10];
        for (int i = 0; i < 10; i++) {
            tableNames[i] = "xp_agreement_app_user_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有点位表名列表(用于全表扫描场景)
     *
     * @return 所有点位表名数组,共10个表
     */
    public static String[] getAllPointTableNames() {
        String[] tableNames = new String[10];
        for (int i = 0; i < 10; i++) {
            tableNames[i] = "xp_point_" + i;
        }
        return tableNames;
    }
    /**
     * 计算分片索引(通用方法)
     *
     * @param shardingValue 分片键值
     * @param shardingCount 分片数量
     * @return 分片索引
     */
    public static int calculateShardingIndex(Long shardingValue, int shardingCount) {
        if (shardingValue == null) {
            log.warn("shardingValue is null, returning 0");
            return 0;
        }
        return (int) (shardingValue % shardingCount);
    }
    /**
     * 获取指定表的分片表名(通用方法)
     *
     * @param baseTableName 基础表名(如: sys_oper_log)
     * @param shardingValue 分片键值
     * @param shardingCount 分片数量
     * @return 实际表名
     */
    public static String getShardingTableName(String baseTableName, Long shardingValue, int shardingCount) {
        int index = calculateShardingIndex(shardingValue, shardingCount);
        String tableName = baseTableName + "_" + index;
        log.debug("baseTableName: {}, shardingValue: {}, shardingCount: {}, calculated table name: {}",
                  baseTableName, shardingValue, shardingCount, tableName);
        return tableName;
    }
    /**
     * 打印所有分表配置信息(用于调试)
     */
    public static void printShardingInfo() {
        log.info("========== Sharding Table Configuration ==========");
        log.info("sys_oper_log: 10 tables, sharding by userId % 10");
        log.info("xp_agreement_app_user: 10 tables, sharding by app_user_id % 10");
        log.info("xp_point: 10 tables, sharding by electronic_area_id % 10");
        log.info("===================================================");
    }
}
xp-robotaxi-itinerary-boot/src/test/java/com/xiaopeng/itinerary/utils/ShardingUtilExample.java
New file
@@ -0,0 +1,29 @@
package com.xiaopeng.itinerary.utils;
import lombok.extern.slf4j.Slf4j;
/**
 * 分表工具使用示例
 * 演示如何使用 ShardingTableUtil 和 ShardingQueryHelper
 */
@Slf4j
public class ShardingUtilExample {
    /**
     * 示例1: 根据用户ID查询订单
     */
    public void test(Long electronicAreaId) {
        // 1. 获取对应的分表名
        String tableName = ShardingTableUtil.getPointTableName(electronicAreaId);
        log.info("用户ID {} 对应的表: {}", electronicAreaId, tableName);
    }
    /**
     * 主方法 - 运行所有示例
     */
    public static void main(String[] args) {
        ShardingUtilExample example = new ShardingUtilExample();
        example.test(47L);
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -107,6 +107,7 @@
        log.info("quoteMatchName:{}", quoteMatchName);
        for (String name : quoteMatchName) {
            String firstElement = redisService.getFirstElement(name);
            log.info("firstElement:{}", firstElement);
            if (firstElement != null) {
                String[] split = firstElement.toString().split("_");
                // 如果未处理 创建新任务
@@ -210,7 +211,7 @@
        processPushOrder(quoteName, count, uid, split, orderNo, xpTradingStrategy, distance, duration, planRule);
        // 最终没找到车
        redisService.popFirstElement(quoteName);
//        redisService.popFirstElement(quoteName);
        // 取消订单
        xpOrderClient.cancelOrder(orderId);
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/ShardingQueryHelper.java
New file
@@ -0,0 +1,285 @@
package com.xiaopeng.order.utils;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
 * 分表查询辅助工具类
 * 提供分表查询的SQL构建和批量查询支持
 *
 * @author auto-generated
 * @date 2026-03-05
 */
@Slf4j
public class ShardingQueryHelper {
    /**
     * 构建单个分表的查询SQL
     *
     * @param baseTableName 基础表名
     * @param shardingValue 分片键值
     * @param shardingCount 分片数量
     * @param whereClause   WHERE子句(不包含WHERE关键字)
     * @return 完整的查询SQL
     */
    public static String buildSingleTableQuery(String baseTableName, Long shardingValue,
                                               int shardingCount, String whereClause) {
        String tableName = ShardingTableUtil.getShardingTableName(baseTableName, shardingValue, shardingCount);
        StringBuilder sql = new StringBuilder("SELECT * FROM ");
        sql.append(tableName);
        if (whereClause != null && !whereClause.trim().isEmpty()) {
            sql.append(" WHERE ").append(whereClause);
        }
        String query = sql.toString();
        log.debug("Generated single table query: {}", query);
        return query;
    }
    /**
     * 构建全表扫描的UNION查询SQL(适用于需要查询所有分表的场景)
     *
     * @param baseTableName 基础表名
     * @param shardingCount 分片数量
     * @param whereClause   WHERE子句(不包含WHERE关键字)
     * @param orderBy       排序字句(不包含ORDER BY关键字)
     * @param limit         限制返回数量,null表示不限制
     * @return UNION查询SQL
     */
    public static String buildUnionAllQuery(String baseTableName, int shardingCount,
                                           String whereClause, String orderBy, Integer limit) {
        StringBuilder sql = new StringBuilder();
        for (int i = 0; i < shardingCount; i++) {
            if (i > 0) {
                sql.append(" UNION ALL ");
            }
            sql.append("SELECT * FROM ").append(baseTableName).append("_").append(i);
            if (whereClause != null && !whereClause.trim().isEmpty()) {
                sql.append(" WHERE ").append(whereClause);
            }
        }
        // 外层排序和限制
        if (orderBy != null && !orderBy.trim().isEmpty()) {
            sql.insert(0, "SELECT * FROM (");
            sql.append(") AS union_result ORDER BY ").append(orderBy);
        }
        if (limit != null && limit > 0) {
            sql.append(" LIMIT ").append(limit);
        }
        String query = sql.toString();
        log.debug("Generated union all query for {} tables: {}", shardingCount, query);
        return query;
    }
    /**
     * 获取需要查询的分表索引列表(基于分片键值范围)
     *
     * @param startValue    起始分片键值
     * @param endValue      结束分片键值
     * @param shardingCount 分片数量
     * @return 需要查询的表索引列表
     */
    public static List<Integer> getShardingIndexesInRange(Long startValue, Long endValue, int shardingCount) {
        List<Integer> indexes = new ArrayList<>();
        if (startValue == null || endValue == null || startValue > endValue) {
            log.warn("Invalid range: start={}, end={}, returning all indexes", startValue, endValue);
            for (int i = 0; i < shardingCount; i++) {
                indexes.add(i);
            }
            return indexes;
        }
        // 计算涉及的分表索引
        for (long value = startValue; value <= endValue; value++) {
            int index = (int) (value % shardingCount);
            if (!indexes.contains(index)) {
                indexes.add(index);
            }
        }
        log.debug("Range query from {} to {} covers indexes: {}", startValue, endValue, indexes);
        return indexes;
    }
    /**
     * 构建基于索引列表的UNION查询
     *
     * @param baseTableName    基础表名
     * @param tableIndexes     要查询的表索引列表
     * @param whereClause      WHERE子句
     * @param orderBy          排序字句
     * @param limit            限制数量
     * @return UNION查询SQL
     */
    public static String buildUnionQueryByIndexes(String baseTableName, List<Integer> tableIndexes,
                                                  String whereClause, String orderBy, Integer limit) {
        if (tableIndexes == null || tableIndexes.isEmpty()) {
            log.warn("No table indexes provided, returning empty query");
            return "";
        }
        StringBuilder sql = new StringBuilder();
        for (int i = 0; i < tableIndexes.size(); i++) {
            if (i > 0) {
                sql.append(" UNION ALL ");
            }
            int tableIndex = tableIndexes.get(i);
            sql.append("SELECT * FROM ").append(baseTableName).append("_").append(tableIndex);
            if (whereClause != null && !whereClause.trim().isEmpty()) {
                sql.append(" WHERE ").append(whereClause);
            }
        }
        // 外层排序和限制
        if (orderBy != null && !orderBy.trim().isEmpty()) {
            sql.insert(0, "SELECT * FROM (");
            sql.append(") AS union_result ORDER BY ").append(orderBy);
        }
        if (limit != null && limit > 0) {
            sql.append(" LIMIT ").append(limit);
        }
        String query = sql.toString();
        log.debug("Generated union query for indexes {}: {}", tableIndexes, query);
        return query;
    }
    /**
     * 构建订单相关表的批量查询SQL示例
     */
    public static class OrderQueryBuilder {
        /**
         * 根据用户ID查询订单
         */
        public static String queryOrderByUserId(Long appUserId, String additionalWhere) {
            String tableName = ShardingTableUtil.getOrderTableName(appUserId);
            StringBuilder sql = new StringBuilder("SELECT * FROM ").append(tableName);
            sql.append(" WHERE app_user_id = ").append(appUserId);
            if (additionalWhere != null && !additionalWhere.trim().isEmpty()) {
                sql.append(" AND ").append(additionalWhere);
            }
            return sql.toString();
        }
        /**
         * 根据订单ID查询订单详情
         */
        public static String queryOrderDetailByOrderId(Long orderId) {
            String tableName = ShardingTableUtil.getOrderDetailTableName(orderId);
            return "SELECT * FROM " + tableName + " WHERE order_id = " + orderId;
        }
        /**
         * 根据订单ID查询订单支付信息
         */
        public static String queryOrderPaymentByOrderId(Long orderId) {
            String tableName = ShardingTableUtil.getOrderPaymentTableName(orderId);
            return "SELECT * FROM " + tableName + " WHERE order_id = " + orderId;
        }
        /**
         * 根据订单ID查询订单评价
         */
        public static String queryOrderEvaluateByOrderId(Long orderId) {
            String tableName = ShardingTableUtil.getOrderEvaluateTableName(orderId);
            return "SELECT * FROM " + tableName + " WHERE order_id = " + orderId;
        }
        /**
         * 根据订单ID查询订单取消记录
         */
        public static String queryOrderCancelByOrderId(Long orderId) {
            String tableName = ShardingTableUtil.getOrderCancelTableName(orderId);
            return "SELECT * FROM " + tableName + " WHERE order_id = " + orderId;
        }
        /**
         * 查询所有订单(全表扫描)
         */
        public static String queryAllOrders(String whereClause, String orderBy, Integer limit) {
            return ShardingQueryHelper.buildUnionAllQuery("xp_order", 20, whereClause, orderBy, limit);
        }
        /**
         * 查询所有订单详情(全表扫描)
         */
        public static String queryAllOrderDetails(String whereClause, String orderBy, Integer limit) {
            return ShardingQueryHelper.buildUnionAllQuery("xp_order_detail", 20, whereClause, orderBy, limit);
        }
    }
    /**
     * 分表查询计数工具
     */
    public static class ShardingCountHelper {
        /**
         * 构建分表计数查询(UNION ALL + SUM)
         */
        public static String buildCountQuery(String baseTableName, int shardingCount, String whereClause) {
            StringBuilder sql = new StringBuilder("SELECT SUM(cnt) AS total_count FROM (");
            for (int i = 0; i < shardingCount; i++) {
                if (i > 0) {
                    sql.append(" UNION ALL ");
                }
                sql.append("SELECT COUNT(*) AS cnt FROM ").append(baseTableName).append("_").append(i);
                if (whereClause != null && !whereClause.trim().isEmpty()) {
                    sql.append(" WHERE ").append(whereClause);
                }
            }
            sql.append(") AS count_result");
            String query = sql.toString();
            log.debug("Generated count query: {}", query);
            return query;
        }
        /**
         * 统计所有订单数量
         */
        public static String countAllOrders(String whereClause) {
            return buildCountQuery("xp_order", 20, whereClause);
        }
    }
    /**
     * 打印查询示例
     */
    public static void printQueryExamples() {
        log.info("========== Sharding Query Examples ==========");
        log.info("1. Query order by userId 12345:");
        log.info("   {}", OrderQueryBuilder.queryOrderByUserId(12345L, "status = 1"));
        log.info("");
        log.info("2. Query order detail by orderId 67890:");
        log.info("   {}", OrderQueryBuilder.queryOrderDetailByOrderId(67890L));
        log.info("");
        log.info("3. Query all orders with status=1 (UNION ALL):");
        log.info("   {}", OrderQueryBuilder.queryAllOrders("status = 1", "create_time DESC", 100));
        log.info("");
        log.info("4. Count all orders:");
        log.info("   {}", ShardingCountHelper.countAllOrders("status IN (9, 10)"));
        log.info("=============================================");
    }
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/utils/ShardingTableUtil.java
New file
@@ -0,0 +1,246 @@
package com.xiaopeng.order.utils;
import lombok.extern.slf4j.Slf4j;
/**
 * 分表工具类
 * 根据 ShardingSphere 配置计算实际的分表名称
 *
 * @author auto-generated
 * @date 2026-03-05
 */
@Slf4j
public class ShardingTableUtil {
    /**
     * 根据用户ID计算订单表的实际表名
     * 分片规则: xp_order_${app_user_id % 20}
     *
     * @param appUserId 用户ID
     * @return 实际表名,如: xp_order_5
     */
    public static String getOrderTableName(Long appUserId) {
        if (appUserId == null) {
            log.warn("appUserId is null, returning default table name");
            return "xp_order_0";
        }
        int tableIndex = (int) (appUserId % 20);
        String tableName = "xp_order_" + tableIndex;
        log.debug("appUserId: {}, calculated table name: {}", appUserId, tableName);
        return tableName;
    }
    /**
     * 根据订单ID计算订单取消表的实际表名
     * 分片规则: xp_order_cancel_${order_id % 20}
     *
     * @param orderId 订单ID
     * @return 实际表名,如: xp_order_cancel_5
     */
    public static String getOrderCancelTableName(Long orderId) {
        if (orderId == null) {
            log.warn("orderId is null, returning default table name");
            return "xp_order_cancel_0";
        }
        int tableIndex = (int) (orderId % 20);
        String tableName = "xp_order_cancel_" + tableIndex;
        log.debug("orderId: {}, calculated table name: {}", orderId, tableName);
        return tableName;
    }
    /**
     * 根据订单ID计算订单详情表的实际表名
     * 分片规则: xp_order_detail_${order_id % 20}
     *
     * @param orderId 订单ID
     * @return 实际表名,如: xp_order_detail_5
     */
    public static String getOrderDetailTableName(Long orderId) {
        if (orderId == null) {
            log.warn("orderId is null, returning default table name");
            return "xp_order_detail_0";
        }
        int tableIndex = (int) (orderId % 20);
        String tableName = "xp_order_detail_" + tableIndex;
        log.debug("orderId: {}, calculated table name: {}", orderId, tableName);
        return tableName;
    }
    /**
     * 根据订单ID计算订单评价表的实际表名
     * 分片规则: xp_order_evaluate_${order_id % 20}
     *
     * @param orderId 订单ID
     * @return 实际表名,如: xp_order_evaluate_5
     */
    public static String getOrderEvaluateTableName(Long orderId) {
        if (orderId == null) {
            log.warn("orderId is null, returning default table name");
            return "xp_order_evaluate_0";
        }
        int tableIndex = (int) (orderId % 20);
        String tableName = "xp_order_evaluate_" + tableIndex;
        log.debug("orderId: {}, calculated table name: {}", orderId, tableName);
        return tableName;
    }
    /**
     * 根据订单ID计算订单支付表的实际表名
     * 分片规则: xp_order_payment_${order_id % 20}
     *
     * @param orderId 订单ID
     * @return 实际表名,如: xp_order_payment_5
     */
    public static String getOrderPaymentTableName(Long orderId) {
        if (orderId == null) {
            log.warn("orderId is null, returning default table name");
            return "xp_order_payment_0";
        }
        int tableIndex = (int) (orderId % 20);
        String tableName = "xp_order_payment_" + tableIndex;
        log.debug("orderId: {}, calculated table name: {}", orderId, tableName);
        return tableName;
    }
    /**
     * 根据任务ID计算订单重新分配表的实际表名
     * 分片规则: xp_order_reassign_${task_id % 10}
     *
     * @param taskId 任务ID
     * @return 实际表名,如: xp_order_reassign_5
     */
    public static String getOrderReassignTableName(Long taskId) {
        if (taskId == null) {
            log.warn("taskId is null, returning default table name");
            return "xp_order_reassign_0";
        }
        int tableIndex = (int) (taskId % 10);
        String tableName = "xp_order_reassign_" + tableIndex;
        log.debug("taskId: {}, calculated table name: {}", taskId, tableName);
        return tableName;
    }
    /**
     * 获取所有订单表名列表(用于全表扫描场景)
     *
     * @return 所有订单表名数组,共20个表
     */
    public static String[] getAllOrderTableNames() {
        String[] tableNames = new String[20];
        for (int i = 0; i < 20; i++) {
            tableNames[i] = "xp_order_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有订单取消表名列表(用于全表扫描场景)
     *
     * @return 所有订单取消表名数组,共20个表
     */
    public static String[] getAllOrderCancelTableNames() {
        String[] tableNames = new String[20];
        for (int i = 0; i < 20; i++) {
            tableNames[i] = "xp_order_cancel_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有订单详情表名列表(用于全表扫描场景)
     *
     * @return 所有订单详情表名数组,共20个表
     */
    public static String[] getAllOrderDetailTableNames() {
        String[] tableNames = new String[20];
        for (int i = 0; i < 20; i++) {
            tableNames[i] = "xp_order_detail_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有订单评价表名列表(用于全表扫描场景)
     *
     * @return 所有订单评价表名数组,共20个表
     */
    public static String[] getAllOrderEvaluateTableNames() {
        String[] tableNames = new String[20];
        for (int i = 0; i < 20; i++) {
            tableNames[i] = "xp_order_evaluate_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有订单支付表名列表(用于全表扫描场景)
     *
     * @return 所有订单支付表名数组,共20个表
     */
    public static String[] getAllOrderPaymentTableNames() {
        String[] tableNames = new String[20];
        for (int i = 0; i < 20; i++) {
            tableNames[i] = "xp_order_payment_" + i;
        }
        return tableNames;
    }
    /**
     * 获取所有订单重新分配表名列表(用于全表扫描场景)
     *
     * @return 所有订单重新分配表名数组,共10个表
     */
    public static String[] getAllOrderReassignTableNames() {
        String[] tableNames = new String[10];
        for (int i = 0; i < 10; i++) {
            tableNames[i] = "xp_order_reassign_" + i;
        }
        return tableNames;
    }
    /**
     * 计算分片索引(通用方法)
     *
     * @param shardingValue 分片键值
     * @param shardingCount 分片数量
     * @return 分片索引
     */
    public static int calculateShardingIndex(Long shardingValue, int shardingCount) {
        if (shardingValue == null) {
            log.warn("shardingValue is null, returning 0");
            return 0;
        }
        return (int) (shardingValue % shardingCount);
    }
    /**
     * 获取指定表的分片表名(通用方法)
     *
     * @param baseTableName 基础表名(如: xp_order)
     * @param shardingValue 分片键值
     * @param shardingCount 分片数量
     * @return 实际表名
     */
    public static String getShardingTableName(String baseTableName, Long shardingValue, int shardingCount) {
        int index = calculateShardingIndex(shardingValue, shardingCount);
        String tableName = baseTableName + "_" + index;
        log.debug("baseTableName: {}, shardingValue: {}, shardingCount: {}, calculated table name: {}",
                  baseTableName, shardingValue, shardingCount, tableName);
        return tableName;
    }
    /**
     * 打印所有分表配置信息(用于调试)
     */
    public static void printShardingInfo() {
        log.info("========== Sharding Table Configuration ==========");
        log.info("xp_order: 20 tables, sharding by app_user_id % 20");
        log.info("xp_order_cancel: 20 tables, sharding by order_id % 20");
        log.info("xp_order_detail: 20 tables, sharding by order_id % 20");
        log.info("xp_order_evaluate: 20 tables, sharding by order_id % 20");
        log.info("xp_order_payment: 20 tables, sharding by order_id % 20");
        log.info("xp_order_reassign: 10 tables, sharding by task_id % 10");
        log.info("===================================================");
    }
}
xp-robotaxi-order-boot/src/test/java/com/xiaopeng/order/ShardingUtilExample.java
New file
@@ -0,0 +1,192 @@
package com.xiaopeng.order;
import com.xiaopeng.order.utils.ShardingQueryHelper;
import com.xiaopeng.order.utils.ShardingTableUtil;
import lombok.extern.slf4j.Slf4j;
/**
 * 分表工具使用示例
 * 演示如何使用 ShardingTableUtil 和 ShardingQueryHelper
 */
@Slf4j
public class ShardingUtilExample {
    /**
     * 示例1: 根据用户ID查询订单
     */
    public void example1_queryOrderByUserId(Long userId) {
        // 1. 获取对应的分表名
        String tableName = ShardingTableUtil.getOrderTableName(userId);
        log.info("用户ID {} 对应的订单表: {}", userId, tableName);
        // 2. 构建查询SQL(在实际开发中,推荐使用MyBatis的动态SQL)
        String sql = String.format("SELECT * FROM %s WHERE app_user_id = %d AND status = 1",
                                   tableName, userId);
        log.info("查询SQL: {}", sql);
    }
    /**
     * 示例2: 根据订单ID查询订单详细信息
     */
    public void example2_queryOrderDetails() {
        Long orderId = 67890L;
        // 查询订单详情表
        String detailTableName = ShardingTableUtil.getOrderDetailTableName(orderId);
        log.info("订单ID {} 对应的详情表: {}", orderId, detailTableName);
        // 查询订单支付表
        String paymentTableName = ShardingTableUtil.getOrderPaymentTableName(orderId);
        log.info("订单ID {} 对应的支付表: {}", orderId, paymentTableName);
        // 查询订单评价表
        String evaluateTableName = ShardingTableUtil.getOrderEvaluateTableName(orderId);
        log.info("订单ID {} 对应的评价表: {}", orderId, evaluateTableName);
        // 使用QueryHelper构建查询
        String detailSql = ShardingQueryHelper.OrderQueryBuilder.queryOrderDetailByOrderId(orderId);
        log.info("订单详情查询SQL: {}", detailSql);
    }
    /**
     * 示例3: 查询所有订单(全表扫描 - UNION ALL)
     */
    public void example3_queryAllOrders() {
        // 场景:查询所有状态为已完成的订单,按创建时间倒序,取前100条
        String sql = ShardingQueryHelper.OrderQueryBuilder.queryAllOrders(
            "status IN (9, 10)",      // WHERE条件
            "create_time DESC",       // 排序
            100                       // 限制数量
        );
        log.info("全表查询SQL (已简化显示):");
        log.info(sql.substring(0, Math.min(500, sql.length())) + "...");
    }
    /**
     * 示例4: 统计订单数量
     */
    public void example4_countOrders() {
        // 统计所有已完成的订单数量
        String countSql = ShardingQueryHelper.ShardingCountHelper.countAllOrders(
            "status IN (9, 10)"
        );
        log.info("订单统计SQL:");
        log.info(countSql);
    }
    /**
     * 示例5: 批量获取表名
     */
    public void example5_getAllTableNames() {
        // 获取所有订单分表的名称
        String[] allTables = ShardingTableUtil.getAllOrderTableNames();
        log.info("所有订单分表(共{}个):", allTables.length);
        for (String table : allTables) {
            log.info("  - {}", table);
        }
    }
    /**
     * 示例6: 计算分表索引
     */
    public void example6_calculateShardingIndex() {
        Long[] userIds = {100L, 200L, 12345L, 67890L, 999999L};
        log.info("用户ID与分表索引映射:");
        for (Long userId : userIds) {
            int index = ShardingTableUtil.calculateShardingIndex(userId, 20);
            String tableName = ShardingTableUtil.getOrderTableName(userId);
            log.info("  用户ID: {} -> 索引: {} -> 表名: {}", userId, index, tableName);
        }
    }
    /**
     * 示例7: 通用分表查询
     */
    public void example7_genericShardingQuery() {
        // 使用通用方法构建查询
        String sql = ShardingQueryHelper.buildSingleTableQuery(
            "xp_order",               // 基础表名
            12345L,                   // 分片键值
            20,                       // 分片数量
            "status = 1 AND create_time > '2026-01-01'"  // WHERE条件
        );
        log.info("通用分表查询SQL: {}", sql);
    }
    /**
     * 示例8: 构建UNION ALL查询
     */
    public void example8_buildUnionAllQuery() {
        String unionSql = ShardingQueryHelper.buildUnionAllQuery(
            "xp_order",                           // 基础表名
            20,                                   // 分片数量
            "status = 1",                        // WHERE条件
            "create_time DESC",                  // 排序
            1000                                 // LIMIT
        );
        log.info("UNION ALL查询SQL (前500字符):");
        log.info(unionSql.substring(0, Math.min(500, unionSql.length())) + "...");
    }
    /**
     * 主方法 - 运行所有示例
     */
    public static void main(String[] args) {
        log.info("========================================");
        log.info("分表工具使用示例");
        log.info("========================================\n");
        ShardingUtilExample example = new ShardingUtilExample();
        log.info(">>> 示例1: 根据用户ID查询订单");
        example.example1_queryOrderByUserId(8107912L);
//        log.info("");
//
//        log.info(">>> 示例2: 根据订单ID查询订单详细信息");
//        example.example2_queryOrderDetails();
//        log.info("");
//
//        log.info(">>> 示例3: 查询所有订单(全表扫描)");
//        example.example3_queryAllOrders();
//        log.info("");
//
//        log.info(">>> 示例4: 统计订单数量");
//        example.example4_countOrders();
//        log.info("");
//
//        log.info(">>> 示例5: 批量获取表名");
//        example.example5_getAllTableNames();
//        log.info("");
//
//        log.info(">>> 示例6: 计算分表索引");
//        example.example6_calculateShardingIndex();
//        log.info("");
//
//        log.info(">>> 示例7: 通用分表查询");
//        example.example7_genericShardingQuery();
//        log.info("");
//
//        log.info(">>> 示例8: 构建UNION ALL查询");
//        example.example8_buildUnionAllQuery();
//        log.info("");
//
//        // 打印分表配置信息
//        log.info("\n========================================");
//        ShardingTableUtil.printShardingInfo();
//
//        // 打印查询示例
//        log.info("");
//        ShardingQueryHelper.printQueryExamples();
//
//        log.info("========================================");
//        log.info("所有示例执行完成!");
//        log.info("========================================");
    }
}