All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.wzc789376152.springboot.shardingjdbc.ShardingService Maven / Gradle / Ivy

The newest version!
package com.github.wzc789376152.springboot.shardingjdbc;


import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageInfo;
import com.github.wzc789376152.springboot.config.SpringContextUtil;
import com.github.wzc789376152.springboot.config.shardingsphere.ShardingPropertics;
import com.github.wzc789376152.springboot.shardingjdbc.function.ShardingCountFunction;
import com.github.wzc789376152.springboot.shardingjdbc.function.ShardingListFunction;
import com.github.wzc789376152.utils.DateUtils;
import lombok.Data;
import org.springframework.scheduling.annotation.AsyncResult;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * 分页搜索服务类
 * 不支持group by查询
 */
public class ShardingService implements IShardingService {
    private final ExecutorService executor;
    private final ExecutorService searchExecutor;
    private final ExecutorService countExecutor;
    private final ShardingCountFunction countMethod;
    private final ShardingListFunction> listMethod;
    private final String field;
    private Date startTime;
    private Date endTime;

    private final ShardingType shardingType;

    public ShardingService(String field, Date startTime, Date endTime, ShardingCountFunction countMethod, ShardingListFunction> listMethod, String asyncName, String searchAsyncName, String countAsyncName, ShardingType shardingType) {
        this.field = field;
        this.startTime = startTime;
        this.endTime = endTime;
        this.countMethod = countMethod;
        this.listMethod = listMethod;
        this.shardingType = shardingType;
        executor = SpringContextUtil.getBean(asyncName, ExecutorService.class);
        countExecutor = SpringContextUtil.getBean(countAsyncName, ExecutorService.class);
        searchExecutor = SpringContextUtil.getBean(searchAsyncName, ExecutorService.class);
    }

    @Override
    public Integer queryCount(QueryWrapper wrapper) throws ExecutionException, InterruptedException {
        return queryCountAsync(wrapper).get();
    }

    @Override
    public Future queryCountAsync(QueryWrapper wrapper) {
        QueryWrapper queryWrapper = wrapper.clone();
        String expressBaseStr = queryWrapper.getCustomSqlSegment();
        String geBaseKey = geKey(expressBaseStr, field);
        String leBaseKey = leKey(expressBaseStr, field);
        if (geBaseKey != null) {
            Date beginTime = (Date) queryWrapper.getParamNameValuePairs().get(geBaseKey);
            if (startTime == null || beginTime.getTime() > startTime.getTime()) {
                startTime = beginTime;
            }
        }
        if (leBaseKey != null) {
            Date finalTime = (Date) queryWrapper.getParamNameValuePairs().get(leBaseKey);
            if (endTime == null || finalTime.getTime() < endTime.getTime()) {
                endTime = finalTime;
            }
        }
        return executor.submit(() -> {
            List betweenList = null;
            switch (shardingType) {
                case Year:
                    betweenList = betweenDateByYears(startTime, endTime);
                    break;
                case Month:
                    betweenList = betweenDateByMonths(startTime, endTime);
            }
            int result = 0;
            List> futureList = new ArrayList<>();
            for (DateBetween between : betweenList) {
                QueryWrapper queryWrapper1 = queryWrapper.clone();
                if (queryWrapper1.getExpression().getGroupBy() != null && queryWrapper1.getExpression().getGroupBy().size() > 0) {
                    for (int j = 0; j < queryWrapper1.getExpression().getGroupBy().size(); j++) {
                        queryWrapper1.getExpression().getGroupBy().remove(j);
                    }
                }
                String expressStr = queryWrapper1.getCustomSqlSegment();
                String geKey = geKey(expressStr, field);
                String leKey = leKey(expressStr, field);
                if (between.getStartDate().getTime() == between.getEndDate().getTime()) {
                    queryWrapper1.eq(geKey == null && leKey == null, field, between.getStartDate());
                } else {
                    queryWrapper1.le(leKey == null, field, between.getEndDate());
                    queryWrapper1.ge(geKey == null, field, between.getStartDate());
                }
                expressStr = queryWrapper1.getCustomSqlSegment();
                geKey = geKey(expressStr, field);
                leKey = leKey(expressStr, field);
                queryWrapper1.getParamNameValuePairs().put(geKey, between.getStartDate());
                queryWrapper1.getParamNameValuePairs().put(leKey, between.getEndDate());
                futureList.add(countExecutor.submit(() -> countMethod.apply(queryWrapper1)));
            }
            for (Future future1 : futureList) {
                try {
                    Integer obj = future1.get();
                    if (obj == null) {
                        obj = 0;
                    }
                    result += obj;
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            return result;
        });
    }

    @Override
    public List queryList(QueryWrapper wrapper, Integer pageNum, Integer pageSize) throws ExecutionException, InterruptedException {
        return queryListAsync(wrapper, pageNum, pageSize).get();
    }

    @Override
    public Future> queryListAsync(QueryWrapper wrapper, Integer pageNum, Integer pageSize) {
        if (listMethod == null || countMethod == null) {
            return AsyncResult.forValue(new ArrayList<>());
        }
        Boolean isAll = false;
        if (pageSize == 0) {
            isAll = true;
        }
        final Integer[] size = {pageSize};
        QueryWrapper queryWrapper = wrapper.clone();
        String expressBaseStr = queryWrapper.getCustomSqlSegment();
        String geBaseKey = geKey(expressBaseStr, field);
        String leBaseKey = leKey(expressBaseStr, field);
        if (geBaseKey != null) {
            Date beginTime = (Date) queryWrapper.getParamNameValuePairs().get(geBaseKey);
            if (beginTime.getTime() > startTime.getTime()) {
                startTime = beginTime;
            }
        }
        if (leBaseKey != null) {
            Date finalTime = (Date) queryWrapper.getParamNameValuePairs().get(leBaseKey);
            if (finalTime.getTime() < endTime.getTime()) {
                endTime = finalTime;
            }
        }
        Boolean finalIsAll = isAll;
        return executor.submit(() -> {
            //按照时间分片
            List betweenList = null;
            switch (shardingType) {
                case Year:
                    betweenList = betweenDateByYears(startTime, endTime);
                    break;
                case Month:
                    betweenList = betweenDateByMonths(startTime, endTime);
            }
            //查询起点
            int beginSize = (pageNum - 1) * size[0];
            int i = 0;
            Map>> resultMap = new HashMap<>();
            boolean isEnd = false;
            //查询每个分片实际数据,多线程
            for (DateBetween between : betweenList) {
                QueryWrapper queryWrapper2 = queryWrapper.clone();
                if (queryWrapper2.getExpression().getGroupBy() != null && queryWrapper2.getExpression().getGroupBy().size() > 0) {
                    for (int j = 0; j < queryWrapper2.getExpression().getGroupBy().size(); j++) {
                        queryWrapper2.getExpression().getGroupBy().remove(j);
                    }
                }
                String expressStr = queryWrapper2.getCustomSqlSegment();
                String geKey = geKey(expressStr, field);
                String leKey = leKey(expressStr, field);
                if (between.getStartDate().getTime() == between.getEndDate().getTime()) {
                    queryWrapper2.eq(geKey == null && leKey == null, field, between.getStartDate());
                } else {
                    queryWrapper2.le(leKey == null, field, between.getEndDate());
                    queryWrapper2.ge(geKey == null, field, between.getStartDate());
                }
                expressStr = queryWrapper2.getCustomSqlSegment();
                geKey = geKey(expressStr, field);
                leKey = leKey(expressStr, field);
                queryWrapper2.getParamNameValuePairs().put(geKey, between.getStartDate());
                queryWrapper2.getParamNameValuePairs().put(leKey, between.getEndDate());
                Integer object = countMethod.apply(queryWrapper2);
                int count = Integer.parseInt(object == null ? "0" : object.toString());
                if (count == 0L) {
                    i++;
                    continue;
                }
                if (beginSize >= count) {
                    //如果查询的起点是比这张表的数据大的,就忽略这张表,查询下一张表,并把起点位置去掉该表的总数
                    beginSize -= count;
                } else {
                    if (isEnd) {
                        break;
                    }
                    Integer limit = size[0];
                    if (limit == 0) {
                        limit = count;
                    }
                    //判断查询的条数是否足够,如果不足够,则查询该表实际数值。如需查询20条,但是该表只有15条
                    if (count - beginSize < size[0]) {
                        limit = count - beginSize;
                    }
                    Integer finalBeginSize = beginSize;
                    Integer finalLimit = limit;
                    QueryWrapper queryWrapper1 = queryWrapper.clone();
                    expressStr = queryWrapper1.getCustomSqlSegment();
                    geKey = geKey(expressStr, field);
                    leKey = leKey(expressStr, field);
                    if (between.getStartDate().getTime() == between.getEndDate().getTime()) {
                        queryWrapper1.eq(geKey == null && leKey == null, field, between.getStartDate());
                    } else {
                        queryWrapper1.le(leKey == null, field, between.getEndDate());
                        queryWrapper1.ge(geKey == null, field, between.getStartDate());
                    }
                    expressStr = queryWrapper1.getCustomSqlSegment();
                    geKey = geKey(expressStr, field);
                    leKey = leKey(expressStr, field);
                    queryWrapper1.getParamNameValuePairs().put(geKey, between.getStartDate());
                    queryWrapper1.getParamNameValuePairs().put(leKey, between.getEndDate());
                    Future> future = searchExecutor.submit(() -> listMethod.apply(queryWrapper1, finalLimit, finalBeginSize));
                    resultMap.put(i, future);
                    beginSize = 0;
                    if (!finalIsAll) {
                        if (size[0] == 0 || limit.equals(size[0])) {
                            isEnd = true;
                        } else {
                            //查询完成将查询的条目减掉,如需查询20条,该表只查了15条,下次查询则只需查询5条
                            size[0] = size[0] - limit;
                        }
                    }
                }
                i++;
            }
            //将查询数据汇总
            List result = new ArrayList<>();
            for (int j = 0; j < i; j++) {
                try {
                    Future> future = resultMap.get(j);
                    if (future == null) {
                        continue;
                    }
                    List o = future.get();
                    result.addAll(o);
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            Date endDate = new Date();
//            System.out.println("查询耗时:" + (endDate.getTime() - beginDate.getTime()) / 1000 + "s");
            return result;
        });
    }

    @Override
    public PageInfo queryPage(QueryWrapper wrapper, Integer pageNum, Integer pageSize) throws ExecutionException, InterruptedException {
        PageInfo pageInfo = new PageInfo<>();
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        Future> listFuture = queryListAsync(wrapper, pageNum, pageSize);
        Future countFuture = queryCountAsync(wrapper);
        pageInfo.setList(listFuture.get());
        pageInfo.setTotal(countFuture.get());
        return pageInfo;
    }

    private String leKey(String sql, String field) {
        boolean hasField = sql.contains(field + " <");
        if (hasField) {
            String key = sql.substring(sql.indexOf(field + " <"));
            key = key.substring(key.indexOf("Pairs") + 6, key.indexOf("}"));
            return key;
        }
        return null;
    }

    private String geKey(String sql, String field) {
        boolean hasField = sql.contains(field + " >");
        if (hasField) {
            String key = sql.substring(sql.indexOf(field + " >"));
            key = key.substring(key.indexOf("Pairs") + 6, key.indexOf("}"));
            return key;
        }
        return null;
    }

    @Data
    private static class DateBetween {
        private Date startDate;
        private Date endDate;
    }

    private static List betweenDateByYears(Date startTime, Date endTime) {
        if (startTime == null) {
            ShardingPropertics shardingPropertics = SpringContextUtil.getBean(ShardingPropertics.class);
            if (shardingPropertics.getMinDate() != null) {
                startTime = shardingPropertics.getMinDate();
            } else {
                startTime = DateUtils.parse("2000-01-01 00:00:00");
            }
        }
        if (endTime == null) {
            endTime = new Date();
        }
        List list = new LinkedList<>();
        int startYear = Integer.parseInt(DateUtils.format(startTime, "yyyy"));
        int endYear = Integer.parseInt(DateUtils.format(endTime, "yyyy"));
        for (int i = endYear; i >= startYear; i--) {
            if (i == endYear) {
                DateBetween between = new DateBetween();
                if (i == startYear) {
                    between.setStartDate(startTime);
                } else {
                    between.setStartDate(DateUtils.parse(i + "-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss"));
                }
                between.setEndDate(endTime);
                list.add(between);
            } else if (i == startYear) {
                DateBetween between = new DateBetween();
                between.setEndDate(DateUtils.parse(i + "-12-31 23:59:59", "yyyy-MM-dd HH:mm:ss"));
                between.setStartDate(startTime);
                list.add(between);
            } else {
                DateBetween between = new DateBetween();
                between.setEndDate(DateUtils.parse(i + "-12-31 23:59:59", "yyyy-MM-dd HH:mm:ss"));
                between.setStartDate(DateUtils.parse(i + "-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss"));
                list.add(between);
            }
        }
        return list;
    }

    private static List betweenDateByMonths(Date startTime, Date endTime) {
        if (startTime == null) {
            ShardingPropertics shardingPropertics = SpringContextUtil.getBean(ShardingPropertics.class);
            if (shardingPropertics.getMinDate() != null) {
                startTime = shardingPropertics.getMinDate();
            } else {
                startTime = DateUtils.parse("2000-01-01 00:00:00");
            }
        }
        if (endTime == null) {
            endTime = new Date();
        }
        if (startTime.getTime() == endTime.getTime()) {
            List betweenList = new ArrayList<>();
            DateBetween between = new DateBetween();
            between.setStartDate(startTime);
            between.setEndDate(endTime);
            betweenList.add(between);
            return betweenList;
        }
        List list = new LinkedList<>();
        Date d1 = startTime;// 定义起始日期
        Date d2 = endTime;// 定义结束日期
        Calendar dd = Calendar.getInstance();// 定义日期实例
        dd.setTime(d1);// 设置日期起始时间
        Calendar cale = Calendar.getInstance();
        Calendar c = Calendar.getInstance();
        c.setTime(d2);
        int startDay = dd.get(Calendar.DAY_OF_MONTH);
        int endDay = c.get(Calendar.DAY_OF_MONTH);
        DateBetween keyValueForDate = null;
        while (dd.getTime().before(d2)) {// 判断是否到结束日期
            keyValueForDate = new DateBetween();
            cale.setTime(dd.getTime());
            if (dd.getTime().equals(d1)) {
                cale.set(Calendar.DAY_OF_MONTH, dd.getActualMaximum(Calendar.DAY_OF_MONTH));
                keyValueForDate.setStartDate(d1);
                Date finishDate = cale.getTime();
                if (finishDate.before(d2)) {
                    cale.set(Calendar.HOUR_OF_DAY, 23);
                    cale.set(Calendar.MINUTE, 59);
                    cale.set(Calendar.SECOND, 59);
                    keyValueForDate.setEndDate(cale.getTime());
                } else {
                    keyValueForDate.setEndDate(d2);
                }

            } else if (dd.get(Calendar.MONTH) == c.get(Calendar.MONTH) && dd.get(Calendar.YEAR) == c.get(Calendar.YEAR)) {
                cale.set(Calendar.DAY_OF_MONTH, 1);//取第一天
                keyValueForDate.setStartDate(cale.getTime());
                keyValueForDate.setEndDate(d2);
            } else {
                cale.set(Calendar.DAY_OF_MONTH, 1);//取第一天
                keyValueForDate.setStartDate(cale.getTime());
                cale.set(Calendar.DAY_OF_MONTH, dd
                        .getActualMaximum(Calendar.DAY_OF_MONTH));
                cale.set(Calendar.HOUR_OF_DAY, 23);
                cale.set(Calendar.MINUTE, 59);
                cale.set(Calendar.SECOND, 59);
                keyValueForDate.setEndDate(cale.getTime());

            }
            list.add(keyValueForDate);
            dd.add(Calendar.MONTH, 1);// 进行当前日期月份加1

        }
        if (endDay < startDay) {
            keyValueForDate = new DateBetween();

            cale.setTime(d2);
            cale.set(Calendar.DAY_OF_MONTH, 1);//取第一天
            cale.set(Calendar.HOUR_OF_DAY, 0);
            cale.set(Calendar.MINUTE, 0);
            cale.set(Calendar.SECOND, 0);
            keyValueForDate.setStartDate(cale.getTime());
            keyValueForDate.setEndDate(d2);
            list.add(keyValueForDate);
        }
        return list.stream().sorted(Comparator.comparing(DateBetween::getStartDate).reversed()).collect(Collectors.toList());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy