|
|
@@ -2,6 +2,7 @@ package com.txz.mall.configurer;
|
|
|
|
|
|
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
|
|
|
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;
|
|
|
+import org.springframework.util.ObjectUtils;
|
|
|
|
|
|
import java.text.ParseException;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
@@ -9,157 +10,446 @@ import java.util.*;
|
|
|
|
|
|
public class StoreOrderInfoDatabaseShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {
|
|
|
|
|
|
-
|
|
|
- private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
- private static final SimpleDateFormat SDFORDERNO = new SimpleDateFormat("yyyyMMdd");
|
|
|
+//
|
|
|
+// private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+// private static final SimpleDateFormat SDFORDERNO = new SimpleDateFormat("yyyyMMdd");
|
|
|
+// private static final Set<Integer> FIRST_HALF_MONTHS = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6));
|
|
|
+// private static final Set<Integer> SECOND_HALF_MONTHS = new HashSet<>(Arrays.asList(7, 8, 9, 10, 11, 12));
|
|
|
+//
|
|
|
+// @Override
|
|
|
+// public Collection<String> doSharding(Collection<String> availableTargets, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
+// // 判断操作类型
|
|
|
+// boolean isInsert = isInsertOperation(shardingValue);
|
|
|
+//
|
|
|
+// // 提取分片键
|
|
|
+// Date createTime = getCreateTime(shardingValue);
|
|
|
+// Long userId = getUserId(shardingValue);
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// // 插入操作必须包含create_time和user_id
|
|
|
+// if (isInsert && (createTime == null || userId == null)) {
|
|
|
+// // throw new IllegalArgumentException("插入数据必须包含create_time和user_id");
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 1-6月数据处理(维持原逻辑)
|
|
|
+// if (createTime != null && isFirstHalfYear(createTime)) {
|
|
|
+// return routeFirstHalf(availableTargets, userId);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 7-12月数据处理
|
|
|
+// if (createTime != null && isSecondHalfYear(createTime)) {
|
|
|
+// return routeSecondHalf(availableTargets, userId);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 查询时无create_time:扫描所有符合条件的库
|
|
|
+// return filterAllDatabases(availableTargets, userId);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 1-6月路由逻辑(维持原逻辑:mall_0/mall_1)
|
|
|
+// private Collection<String> routeFirstHalf(Collection<String> availableTargets, Long userId) {
|
|
|
+// if (userId != null) {
|
|
|
+// // String lastFour = getLastFourDigits(userId);
|
|
|
+// long dbIndex = userId % 2; // 0→mall_0,1→mall_1
|
|
|
+// String targetDb = "ds" + dbIndex;
|
|
|
+// if (availableTargets.contains(targetDb)) {
|
|
|
+// return Collections.singleton(targetDb);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// // 查询时无user_id:扫描1-6月的库
|
|
|
+// return Arrays.asList("ds0", "ds1");
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 7-12月路由逻辑(mall_1/mall_2)
|
|
|
+// private Collection<String> routeSecondHalf(Collection<String> availableTargets, Long userId) {
|
|
|
+// if (userId != null) {
|
|
|
+// //String lastFour = getLastFourDigits(userId);
|
|
|
+// long dbIndex = 2 + (userId % 2); // 1→mall_1,2→mall_2
|
|
|
+// String targetDb = "ds" + dbIndex;
|
|
|
+// if (availableTargets.contains(targetDb)) {
|
|
|
+// return Collections.singleton(targetDb);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// // 查询时无user_id:扫描7-12月的库
|
|
|
+// return Arrays.asList("ds2", "ds3");
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 判断是否为插入操作
|
|
|
+// private boolean isInsertOperation(ComplexKeysShardingValue<?> shardingValue) {
|
|
|
+// //return shardingValue.getSqlType() != null && shardingValue.getSqlType().name().startsWith("INSERT");
|
|
|
+//
|
|
|
+// //shardingValue
|
|
|
+// return true;
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 提取并解析create_time
|
|
|
+// private Date getCreateTime(ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
+// Map<String, Collection<Comparable<?>>> values = shardingValue.getColumnNameAndShardingValuesMap();
|
|
|
+//// if (values.containsKey("create_time") && !values.get("create_time").isEmpty()) {
|
|
|
+//// Object value = values.get("create_time").iterator().next();
|
|
|
+//// if (value instanceof Date) return (Date) value;
|
|
|
+//// try {
|
|
|
+//// return SDF.parse(value.toString());
|
|
|
+//// } catch (ParseException e) {
|
|
|
+//// throw new RuntimeException("create_time格式错误,应为yyyy-MM-dd HH:mm:ss");
|
|
|
+//// }
|
|
|
+//// }
|
|
|
+//
|
|
|
+//
|
|
|
+// if (values.containsKey("order_no") && !values.get("order_no").isEmpty()) {
|
|
|
+// String orderId = (String) values.get("order_no").iterator().next();
|
|
|
+// // 提取日期位并转换为Date类型
|
|
|
+// String dateStr = "20"+orderId.substring(2, 8);
|
|
|
+// try {
|
|
|
+// return SDFORDERNO.parse(dateStr);
|
|
|
+// } catch (ParseException e) {
|
|
|
+// throw new RuntimeException("StoreOrderInfoDatabaseShardingAlgorithm从订单号中提取日期错误"+dateStr);
|
|
|
+// }
|
|
|
+//
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 提取user_id
|
|
|
+// private Long getUserId(ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
+// Map<String, Collection<Comparable<?>>> values = shardingValue.getColumnNameAndShardingValuesMap();
|
|
|
+//// if (values.containsKey("uid") && !values.get("uid").isEmpty()) {
|
|
|
+//// Long uid = (Long) values.get("uid").iterator().next();
|
|
|
+//// return uid % 10000;
|
|
|
+//// }
|
|
|
+//
|
|
|
+// if (values.containsKey("order_no") && !values.get("order_no").isEmpty()) {
|
|
|
+// String orderId = (String) values.get("order_no").iterator().next();
|
|
|
+// // 提取后4位并转换为long类型
|
|
|
+// String lastFourStr = orderId.substring(orderId.length() - 4);
|
|
|
+// return Long.parseLong(lastFourStr);
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 判断是否为1-6月
|
|
|
+// private boolean isFirstHalfYear(Date date) {
|
|
|
+// Calendar calendar = Calendar.getInstance();
|
|
|
+// calendar.setTime(date);
|
|
|
+// return FIRST_HALF_MONTHS.contains(calendar.get(Calendar.MONTH) + 1);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 判断是否为7-12月
|
|
|
+// private boolean isSecondHalfYear(Date date) {
|
|
|
+// Calendar calendar = Calendar.getInstance();
|
|
|
+// calendar.setTime(date);
|
|
|
+// return SECOND_HALF_MONTHS.contains(calendar.get(Calendar.MONTH) + 1);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 获取user_id后四位
|
|
|
+// private String getLastFourDigits(String value) {
|
|
|
+// if (value == null || value.isEmpty()) return "0";
|
|
|
+// return value.substring(Math.max(0, value.length() - 4));
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 无create_time时的全量库过滤
|
|
|
+// private Collection<String> filterAllDatabases(Collection<String> availableTargets, Long userId) {
|
|
|
+// if (userId != null) {
|
|
|
+// // 有user_id但无时间时,需扫描所有可能的库(mall_0/mall_1/mall_2)
|
|
|
+// return Arrays.asList("ds0", "ds1", "ds2","ds3");
|
|
|
+// }
|
|
|
+// // 无任何条件时扫描所有库
|
|
|
+// return availableTargets;
|
|
|
+// }
|
|
|
+//
|
|
|
+private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ private static final SimpleDateFormat SDF_ORDER_NO = new SimpleDateFormat("yyyyMMdd");
|
|
|
private static final Set<Integer> FIRST_HALF_MONTHS = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6));
|
|
|
private static final Set<Integer> SECOND_HALF_MONTHS = new HashSet<>(Arrays.asList(7, 8, 9, 10, 11, 12));
|
|
|
|
|
|
@Override
|
|
|
public Collection<String> doSharding(Collection<String> availableTargets, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
- // 判断操作类型
|
|
|
- boolean isInsert = isInsertOperation(shardingValue);
|
|
|
+ // 优先处理order_id IN条件
|
|
|
+ Map<String, List<Long>> orderIdDbMap = getOrderIdDbMap(shardingValue);
|
|
|
+ if (!orderIdDbMap.isEmpty()) {
|
|
|
+ Set<String> targetDbs = new HashSet<>();
|
|
|
+ for (List<Long> params : orderIdDbMap.values()) {
|
|
|
+ Date createTime = new Date(params.get(0));
|
|
|
+ Long userId = params.get(1);
|
|
|
+ targetDbs.addAll(routeByTimeAndUserId(availableTargets, createTime, userId));
|
|
|
+ }
|
|
|
+ return targetDbs.isEmpty() ? availableTargets : targetDbs;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理无order_id的情况(如uid+create_time范围)
|
|
|
+ return handleNonOrderIdSharding(availableTargets, shardingValue);
|
|
|
+ }
|
|
|
|
|
|
- // 提取分片键
|
|
|
- Date createTime = getCreateTime(shardingValue);
|
|
|
+ /**
|
|
|
+ * 解析所有order_id,提取时间和用户ID
|
|
|
+ */
|
|
|
+ private Map<String, List<Long>> getOrderIdDbMap(ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
+ Map<String, Collection<Comparable<?>>> values = shardingValue.getColumnNameAndShardingValuesMap();
|
|
|
+ Map<String, List<Long>> result = new HashMap<>();
|
|
|
+
|
|
|
+ if (values.containsKey("order_no") && !values.get("order_no").isEmpty()) {
|
|
|
+ for (Comparable<?> val : values.get("order_no")) {
|
|
|
+ String orderId = (String) val;
|
|
|
+ try {
|
|
|
+ String dateStr = "20" + orderId.substring(2, 8);
|
|
|
+ Date createTime = SDF_ORDER_NO.parse(dateStr);
|
|
|
+ String lastFour = orderId.substring(orderId.length() - 4);
|
|
|
+ Long userId = Long.parseLong(lastFour);
|
|
|
+ result.put(orderId, Arrays.asList(createTime.getTime(), userId));
|
|
|
+ } catch (ParseException | StringIndexOutOfBoundsException e) {
|
|
|
+ throw new RuntimeException("解析order_no分库条件失败: " + orderId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理无order_id的情况(支持create_time范围查询)
|
|
|
+ */
|
|
|
+ private Collection<String> handleNonOrderIdSharding(Collection<String> availableTargets, ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
+ // 提取create_time的范围(start和end)
|
|
|
+ StoreOrderInfoDatabaseShardingAlgorithm.DateRange createTimeRange = getCreateTimeRange(shardingValue);
|
|
|
Long userId = getUserId(shardingValue);
|
|
|
|
|
|
+ // 有时间范围时,按范围路由
|
|
|
+ if (createTimeRange != null) {
|
|
|
+ Set<String> targetDbs = new HashSet<>();
|
|
|
+ // 判断是否与1-6月重叠
|
|
|
+ if (isRangeOverlapFirstHalf(createTimeRange)) {
|
|
|
+ targetDbs.addAll(routeFirstHalf(availableTargets, userId));
|
|
|
+ }
|
|
|
+ // 判断是否与7-12月重叠
|
|
|
+ if (isRangeOverlapSecondHalf(createTimeRange)) {
|
|
|
+ targetDbs.addAll(routeSecondHalf(availableTargets, userId));
|
|
|
+ }
|
|
|
+ return targetDbs.isEmpty() ? availableTargets : targetDbs;
|
|
|
+ }
|
|
|
|
|
|
+ // 无时间范围时,全库扫描
|
|
|
+ return filterAllDatabases(availableTargets, userId);
|
|
|
+ }
|
|
|
|
|
|
- // 插入操作必须包含create_time和user_id
|
|
|
- if (isInsert && (createTime == null || userId == null)) {
|
|
|
- // throw new IllegalArgumentException("插入数据必须包含create_time和user_id");
|
|
|
+ /**
|
|
|
+ * 提取create_time的范围值(支持>=和<=)
|
|
|
+ */
|
|
|
+ private StoreOrderInfoDatabaseShardingAlgorithm.DateRange getCreateTimeRange(ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
+ // 1. 从范围条件集合中获取create_time的范围值
|
|
|
+ Map<String, com.google.common.collect.Range<Comparable<?>>> rangeValuesMap = shardingValue.getColumnNameAndRangeValuesMap();
|
|
|
+ com.google.common.collect.Range<Comparable<?>> createTimeRanges = rangeValuesMap.get("create_time");
|
|
|
+
|
|
|
+ Date start = null;
|
|
|
+ Date end = null;
|
|
|
+ // 若没有create_time的范围条件,返回null
|
|
|
+// if (createTimeRanges == null || createTimeRanges.isEmpty()) {
|
|
|
+// return null;
|
|
|
+// }
|
|
|
+ if(!ObjectUtils.isEmpty(createTimeRanges)){
|
|
|
+ if (createTimeRanges.hasLowerBound()) {
|
|
|
+ Comparable<?> lowerVal = createTimeRanges.lowerEndpoint();
|
|
|
+ start = parseDate(lowerVal);
|
|
|
+ }
|
|
|
+ // 提取上界(<=)
|
|
|
+ if (createTimeRanges.hasUpperBound()) {
|
|
|
+ Comparable<?> upperVal = createTimeRanges.upperEndpoint();
|
|
|
+ end = parseDate(upperVal);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 1-6月数据处理(维持原逻辑)
|
|
|
- if (createTime != null && isFirstHalfYear(createTime)) {
|
|
|
- return routeFirstHalf(availableTargets, userId);
|
|
|
+
|
|
|
+ // 3. 兼容等值条件(如果存在create_time = ?,从精确值中提取)
|
|
|
+ if (start == null && end == null) {
|
|
|
+ Map<String, Collection<Comparable<?>>> preciseValuesMap = shardingValue.getColumnNameAndShardingValuesMap();
|
|
|
+ Collection<Comparable<?>> createTimePrecise = preciseValuesMap.get("create_time");
|
|
|
+ if (createTimePrecise != null && !createTimePrecise.isEmpty()) {
|
|
|
+ Comparable<?> preciseVal = createTimePrecise.iterator().next();
|
|
|
+ Date date = parseDate(preciseVal);
|
|
|
+ start = date;
|
|
|
+ end = date;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 7-12月数据处理
|
|
|
- if (createTime != null && isSecondHalfYear(createTime)) {
|
|
|
- return routeSecondHalf(availableTargets, userId);
|
|
|
+ return (start != null || end != null) ? new StoreOrderInfoDatabaseShardingAlgorithm.DateRange(start, end) : null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断时间范围是否与1-6月重叠
|
|
|
+ */
|
|
|
+ private boolean isRangeOverlapFirstHalf(StoreOrderInfoDatabaseShardingAlgorithm.DateRange range) {
|
|
|
+ Calendar firstHalfStart = Calendar.getInstance();
|
|
|
+ firstHalfStart.set(Calendar.MONTH, 0); // 1月
|
|
|
+ firstHalfStart.set(Calendar.DAY_OF_MONTH, 1);
|
|
|
+ firstHalfStart.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ firstHalfStart.set(Calendar.MINUTE, 0);
|
|
|
+ firstHalfStart.set(Calendar.SECOND, 0);
|
|
|
+
|
|
|
+ Calendar firstHalfEnd = Calendar.getInstance();
|
|
|
+ firstHalfEnd.set(Calendar.MONTH, 5); // 6月
|
|
|
+ firstHalfEnd.set(Calendar.DAY_OF_MONTH, 30);
|
|
|
+ firstHalfEnd.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ firstHalfEnd.set(Calendar.MINUTE, 59);
|
|
|
+ firstHalfEnd.set(Calendar.SECOND, 59);
|
|
|
+
|
|
|
+ return isOverlap(range, new StoreOrderInfoDatabaseShardingAlgorithm.DateRange(firstHalfStart.getTime(), firstHalfEnd.getTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断时间范围是否与7-12月重叠
|
|
|
+ */
|
|
|
+ private boolean isRangeOverlapSecondHalf(StoreOrderInfoDatabaseShardingAlgorithm.DateRange range) {
|
|
|
+ Calendar secondHalfStart = Calendar.getInstance();
|
|
|
+ secondHalfStart.set(Calendar.MONTH, 6); // 7月
|
|
|
+ secondHalfStart.set(Calendar.DAY_OF_MONTH, 1);
|
|
|
+ secondHalfStart.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ secondHalfStart.set(Calendar.MINUTE, 0);
|
|
|
+ secondHalfStart.set(Calendar.SECOND, 0);
|
|
|
+
|
|
|
+ Calendar secondHalfEnd = Calendar.getInstance();
|
|
|
+ secondHalfEnd.set(Calendar.MONTH, 11); // 12月
|
|
|
+ secondHalfEnd.set(Calendar.DAY_OF_MONTH, 31);
|
|
|
+ secondHalfEnd.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ secondHalfEnd.set(Calendar.MINUTE, 59);
|
|
|
+ secondHalfEnd.set(Calendar.SECOND, 59);
|
|
|
+
|
|
|
+ return isOverlap(range, new StoreOrderInfoDatabaseShardingAlgorithm.DateRange(secondHalfStart.getTime(), secondHalfEnd.getTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断两个时间范围是否重叠
|
|
|
+ */
|
|
|
+ private boolean isOverlap(StoreOrderInfoDatabaseShardingAlgorithm.DateRange range1, StoreOrderInfoDatabaseShardingAlgorithm.DateRange range2) {
|
|
|
+ // 范围1在范围2之前(不重叠)
|
|
|
+ if (range1.getEnd() != null && range2.getStart() != null
|
|
|
+ && range1.getEnd().before(range2.getStart())) {
|
|
|
+ return false;
|
|
|
}
|
|
|
+ // 范围1在范围2之后(不重叠)
|
|
|
+ if (range1.getStart() != null && range2.getEnd() != null
|
|
|
+ && range1.getStart().after(range2.getEnd())) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 其他情况均重叠
|
|
|
+ return true;
|
|
|
+ }
|
|
|
|
|
|
- // 查询时无create_time:扫描所有符合条件的库
|
|
|
- return filterAllDatabases(availableTargets, userId);
|
|
|
+ /**
|
|
|
+ * 根据时间和用户ID路由数据库
|
|
|
+ */
|
|
|
+ private Collection<String> routeByTimeAndUserId(Collection<String> availableTargets, Date createTime, Long userId) {
|
|
|
+ if (isFirstHalfYear(createTime)) {
|
|
|
+ return routeFirstHalf(availableTargets, userId);
|
|
|
+ } else if (isSecondHalfYear(createTime)) {
|
|
|
+ return routeSecondHalf(availableTargets, userId);
|
|
|
+ }
|
|
|
+ return availableTargets;
|
|
|
}
|
|
|
|
|
|
- // 1-6月路由逻辑(维持原逻辑:mall_0/mall_1)
|
|
|
+ /**
|
|
|
+ * 1-6月路由(ds0/ds1)
|
|
|
+ */
|
|
|
private Collection<String> routeFirstHalf(Collection<String> availableTargets, Long userId) {
|
|
|
if (userId != null) {
|
|
|
- // String lastFour = getLastFourDigits(userId);
|
|
|
- long dbIndex = userId % 2; // 0→mall_0,1→mall_1
|
|
|
+ long dbIndex = userId % 2;
|
|
|
String targetDb = "ds" + dbIndex;
|
|
|
if (availableTargets.contains(targetDb)) {
|
|
|
return Collections.singleton(targetDb);
|
|
|
}
|
|
|
}
|
|
|
- // 查询时无user_id:扫描1-6月的库
|
|
|
return Arrays.asList("ds0", "ds1");
|
|
|
}
|
|
|
|
|
|
- // 7-12月路由逻辑(mall_1/mall_2)
|
|
|
+ /**
|
|
|
+ * 7-12月路由(ds2/ds3)
|
|
|
+ */
|
|
|
private Collection<String> routeSecondHalf(Collection<String> availableTargets, Long userId) {
|
|
|
if (userId != null) {
|
|
|
- //String lastFour = getLastFourDigits(userId);
|
|
|
- long dbIndex = 2 + (userId % 2); // 1→mall_1,2→mall_2
|
|
|
+ long dbIndex = 2 + (userId % 2); // 2或3
|
|
|
String targetDb = "ds" + dbIndex;
|
|
|
if (availableTargets.contains(targetDb)) {
|
|
|
return Collections.singleton(targetDb);
|
|
|
}
|
|
|
}
|
|
|
- // 查询时无user_id:扫描7-12月的库
|
|
|
return Arrays.asList("ds2", "ds3");
|
|
|
}
|
|
|
|
|
|
- // 判断是否为插入操作
|
|
|
- private boolean isInsertOperation(ComplexKeysShardingValue<?> shardingValue) {
|
|
|
- //return shardingValue.getSqlType() != null && shardingValue.getSqlType().name().startsWith("INSERT");
|
|
|
-
|
|
|
- //shardingValue
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- // 提取并解析create_time
|
|
|
- private Date getCreateTime(ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
- Map<String, Collection<Comparable<?>>> values = shardingValue.getColumnNameAndShardingValuesMap();
|
|
|
-// if (values.containsKey("create_time") && !values.get("create_time").isEmpty()) {
|
|
|
-// Object value = values.get("create_time").iterator().next();
|
|
|
-// if (value instanceof Date) return (Date) value;
|
|
|
-// try {
|
|
|
-// return SDF.parse(value.toString());
|
|
|
-// } catch (ParseException e) {
|
|
|
-// throw new RuntimeException("create_time格式错误,应为yyyy-MM-dd HH:mm:ss");
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
- if (values.containsKey("order_no") && !values.get("order_no").isEmpty()) {
|
|
|
- String orderId = (String) values.get("order_no").iterator().next();
|
|
|
- // 提取日期位并转换为Date类型
|
|
|
- String dateStr = "20"+orderId.substring(2, 8);
|
|
|
- try {
|
|
|
- return SDFORDERNO.parse(dateStr);
|
|
|
- } catch (ParseException e) {
|
|
|
- throw new RuntimeException("StoreOrderInfoDatabaseShardingAlgorithm从订单号中提取日期错误"+dateStr);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- // 提取user_id
|
|
|
+ /**
|
|
|
+ * 提取uid(非order_id场景)
|
|
|
+ */
|
|
|
private Long getUserId(ComplexKeysShardingValue<Comparable<?>> shardingValue) {
|
|
|
Map<String, Collection<Comparable<?>>> values = shardingValue.getColumnNameAndShardingValuesMap();
|
|
|
-// if (values.containsKey("uid") && !values.get("uid").isEmpty()) {
|
|
|
-// Long uid = (Long) values.get("uid").iterator().next();
|
|
|
-// return uid % 10000;
|
|
|
-// }
|
|
|
-
|
|
|
- if (values.containsKey("order_no") && !values.get("order_no").isEmpty()) {
|
|
|
- String orderId = (String) values.get("order_no").iterator().next();
|
|
|
- // 提取后4位并转换为long类型
|
|
|
- String lastFourStr = orderId.substring(orderId.length() - 4);
|
|
|
- return Long.parseLong(lastFourStr);
|
|
|
+ if (values.containsKey("uid") && !values.get("uid").isEmpty()) {
|
|
|
+ Long uid = (Long) values.get("uid").iterator().next();
|
|
|
+ return uid % 10000;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- // 判断是否为1-6月
|
|
|
+ /**
|
|
|
+ * 判断是否为1-6月
|
|
|
+ */
|
|
|
private boolean isFirstHalfYear(Date date) {
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
calendar.setTime(date);
|
|
|
return FIRST_HALF_MONTHS.contains(calendar.get(Calendar.MONTH) + 1);
|
|
|
}
|
|
|
|
|
|
- // 判断是否为7-12月
|
|
|
+ /**
|
|
|
+ * 判断是否为7-12月
|
|
|
+ */
|
|
|
private boolean isSecondHalfYear(Date date) {
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
calendar.setTime(date);
|
|
|
return SECOND_HALF_MONTHS.contains(calendar.get(Calendar.MONTH) + 1);
|
|
|
}
|
|
|
|
|
|
- // 获取user_id后四位
|
|
|
- private String getLastFourDigits(String value) {
|
|
|
- if (value == null || value.isEmpty()) return "0";
|
|
|
- return value.substring(Math.max(0, value.length() - 4));
|
|
|
- }
|
|
|
-
|
|
|
- // 无create_time时的全量库过滤
|
|
|
+ /**
|
|
|
+ * 无时间条件时的全库过滤
|
|
|
+ */
|
|
|
private Collection<String> filterAllDatabases(Collection<String> availableTargets, Long userId) {
|
|
|
if (userId != null) {
|
|
|
- // 有user_id但无时间时,需扫描所有可能的库(mall_0/mall_1/mall_2)
|
|
|
- return Arrays.asList("ds0", "ds1", "ds2","ds3");
|
|
|
+ return Arrays.asList("ds0", "ds1", "ds2", "ds3");
|
|
|
}
|
|
|
- // 无任何条件时扫描所有库
|
|
|
return availableTargets;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 解析时间对象为Date
|
|
|
+ */
|
|
|
+ private Date parseDate(Object value) {
|
|
|
+ if (value instanceof Date) {
|
|
|
+ return (Date) value;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return SDF.parse(value.toString());
|
|
|
+ } catch (ParseException e) {
|
|
|
+ throw new RuntimeException("时间格式错误: " + value, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内部类:表示时间范围(start <= create_time <= end)
|
|
|
+ */
|
|
|
+ private static class DateRange {
|
|
|
+ private final Date start;
|
|
|
+ private final Date end;
|
|
|
+
|
|
|
+ public DateRange(Date start, Date end) {
|
|
|
+ this.start = start;
|
|
|
+ this.end = end;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Date getStart() {
|
|
|
+ return start;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Date getEnd() {
|
|
|
+ return end;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|