數據庫大數據量導出多線程版本源碼部分

package com.alibaba.crm.finance.bo.export;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

import com.ali.shy.dao.Queryable;
import com.ali.shy.util.JSON;
import com.ali.shy.util.json.ParseException;
import com.alibaba.crm.finance.biz.common.BizConstant;
import com.alibaba.crm.finance.biz.export.CompressedFilesUtil;
import com.alibaba.crm.finance.biz.export.NotepadRender;
import com.alibaba.crm.finance.common.log.LogModel;
import com.alibaba.crm.finance.common.log.LogUtil;
import com.alibaba.crm.finance.dataobject.base.sys.FinExportTask;

/**
 * @author longer 2012-4-16 \u4e0b\u53485:04:55
 */
@SuppressWarnings({ "unchecked" })
public class QueueGenerateExcel implements BeanFactoryAware, ExportStartNow {

    private FinExportTaskBo        finExportTaskBo;

    private NotepadRender          notepadRender;

    private static final Logger    LOG              = Logger.getLogger(QueueGenerateExcel.class);

    private static final Object    LOCK             = new Object();
    private static final int       THREAD_POOL_SIZE = 3;

    private static ExecutorService EXECUTOR_SERVICE = null;
    static {
        EXECUTOR_SERVICE = Executors.newFixedThreadPool(THREAD_POOL_SIZE, new ThreadFactory() {

            final AtomicInteger threadNumber = new AtomicInteger(1);

            public Thread newThread(Runnable r) {
                ThreadGroup group = Thread.currentThread().getThreadGroup();
                Thread t = new Thread(group, r, "export-pool-" + threadNumber.getAndIncrement(), 0);
                return t;
            }
        });
    }

    public void setNotepadRender(NotepadRender notepadRender) {
        this.notepadRender = notepadRender;
    }

    private static BeanFactory mFact;

    public void setBeanFactory(BeanFactory beanFactory) {
        mFact = beanFactory;
    }

    public void setFinExportTaskBo(FinExportTaskBo finExportTaskBo) {
        this.finExportTaskBo = finExportTaskBo;
    }

    /*
     * (non-Javadoc)
     * @see com.alibaba.crm.finance.bo.export.ExportStartNow#startExportNow()
     */
    public void startExportNow() {
        synchronized (LOCK) {
            LOCK.notifyAll();
        }
    }

    public void init() {
        try {
            for (int i = 0; i < THREAD_POOL_SIZE; i++) {
                EXECUTOR_SERVICE.execute(new Generate(i));
            }
            EXECUTOR_SERVICE.shutdown();
        } catch (Exception e) {
            LogModel model = new LogModel("QueueGenerateExcel", "\u5bfc\u51fa\u5b9a\u65f6\u949f", e);
            LogUtil.error(LOG, model);
        }
    }

    public void close() {
        EXECUTOR_SERVICE.shutdownNow();
    }

    private class Generate extends Thread {

        private static final int  COMPUTE_TIME_TIMES        = 10;
        private static final int  DEFFER_MIN_PAGE_SIZE      = 1000;
        private static final int  ONE_SECOND                = 1 * 1000;
        private static final int  PAGE_PRE_SIZE             = 4000;

        private static final int  WAIT_TIMEOUT_FOR_OUT_NULL = 1000;
        private static final long WAIT_TIMEOUT_FOR_NULL     = 2 * 60 * 1000L;

        public Generate(int i){
            super("Generate_export_" + i);
        }

        public void run() {
            LogModel model = new LogModel("QueueGenerateExcel Generate run");
            while (Boolean.TRUE) {
                FinExportTask finExportTask = null;
                try {
                    finExportTask = loadNextTask();
                    if (finExportTask != null) {
                        deleteBeforeFile(finExportTask.getFileName());
                        if (executeOneTask(finExportTask)) {
                            finExportTaskBo.finishTheTask(finExportTask.getId(), finExportTask.getFileName(),
                                                          finExportTask.getFileSize());
                            LogUtil.logInfo(model, LOG, finExportTask + " finish!!");
                        } else {
                            LogUtil.logInfo(model, LOG, finExportTask + " break!!");
                        }

                    }
                    sleep(finExportTask);
                } catch (Exception e) {
                    if (finExportTask != null) {
                        finExportTask.setServiceEndDate(new Date());
                        finExportTaskBo.failureTheTsak(finExportTask.getId());
                    }
                    LogUtil.logError(model, LOG, e.getMessage(), e);
                }
            }
        }

        private void deleteBeforeFile(String fileName) {
            LogModel model = new LogModel("QueueGenerateExcel Generate deleteBeforeFile");
            try {
                LogUtil.logInfo(model, LOG, "deleteBeforeFile START");
                File f = new File(fileName);
                if (f.exists()) {
                    f.renameTo(new File(fileName + "." + new Date().getTime() + ".back"));
                }
                File frar = new File(fileName + CompressedFilesUtil.FILE_STYLE);
                if (frar.exists()) {
                    frar.renameTo(new File(fileName + CompressedFilesUtil.FILE_STYLE + "." + new Date().getTime()
                                           + ".back"));
                }
                LogUtil.logInfo(model, LOG, "deleteBeforeFile END");
            } catch (Exception e) {
                LogUtil.logError(model, LOG, e.getMessage(), e);
            }
        }

        private void sleep(FinExportTask finExportTask) throws InterruptedException {
            if (finExportTask == null) {
                synchronized (LOCK) {
                    LOCK.wait(WAIT_TIMEOUT_FOR_NULL);// wait 2min
                }
            } else {
                Thread.sleep(WAIT_TIMEOUT_FOR_OUT_NULL);// sleep 1s
            }
        }

        private FinExportTask loadNextTask() throws InterruptedException {
            LogModel model = new LogModel("loadNextTask");
            while (Boolean.TRUE) {
                FinExportTask finExportTask = finExportTaskBo.loadNextTask();
                if (finExportTask == null) {
                    LogUtil.logInfo(model, LOG, "all finExportTask has  finish !");
                    return finExportTask;
                }
                if (finExportTaskBo.startTheTask(finExportTask)) {
                    finExportTask.setStatus(BizConstant.EXPORT_TASK_STATUS_SERVICE);
                    finExportTask.setServiceBeginDate(new Date());
                    LogUtil.logInfo(model, LOG, finExportTask + " start!");
                    return finExportTask;
                } else {
                    LogUtil.logInfo(model, LOG, finExportTask + " is in service!");
                }
                Thread.sleep(ONE_SECOND);
            }
            return null;
        }

        private Export genExport(FinExportTask finExportTask) throws ParseException {
            Export e = new Export();
            String json = finExportTask.getSearchCondition();
            Map<String, Object> data = (Map<String, Object>) JSON.parse(json);

            String fileName = finExportTask.getFileName();
            String action = String.valueOf(data.get("dao"));

            String query = String.valueOf(data.get("query"));
            if ("null".equals(query)) {
                query = null;
            }
            int max = Integer.valueOf(String.valueOf(data.get("max")));
            int skip = Integer.valueOf(String.valueOf(data.get("skip")));
            e.setSkip(skip);
            e.setAction(action);
            e.setFileName(fileName);
            e.setMax(max);
            e.setQuery(query);
            e.setData(data);
            return e;
        }

        private Boolean executeOneTask(FinExportTask finExportTask) throws ParseException, SQLException, IOException,
                                                                   InterruptedException {
            LogModel model = new LogModel("executeOneTask");
            Export e = genExport(finExportTask);
            reviseMax(e);
            int pageSize = e.getMax() / PAGE_PRE_SIZE + 1;// \u9875\u6570
            if ((e.getMax() % PAGE_PRE_SIZE) == 0) {
                pageSize = pageSize - 1;
            }

            Queue<Long> times = new LinkedList<Long>();
            for (int i = 0; i < pageSize; i++) {
                if (breakTask(finExportTask)) {
                    LogUtil.logInfo(model, LOG, finExportTask + " break!!");
                    return Boolean.FALSE;
                }
                int skipp = e.getSkip() + i * PAGE_PRE_SIZE;
                int pagePreSize = PAGE_PRE_SIZE;
                if (i == pageSize - 1) {
                    pagePreSize = e.getMax() - (pageSize - 1) * PAGE_PRE_SIZE;
                    // FOR DEEFER
                    if (pagePreSize <= DEFFER_MIN_PAGE_SIZE && e.getAction().equals("defferDaoModelAction")) {
                        pagePreSize = DEFFER_MIN_PAGE_SIZE + 1;
                    }
                }
                long startTime = new Date().getTime();
                List<Object> datas = getDao(e.getAction()).queryForList(e.getQuery(), e.getData(), skipp, pagePreSize);
                notepadRender.trans(datas, new File(e.getFileName()));

                computeRemainingTime(finExportTask, pageSize, times, i, startTime);
                // for compatibility
                if (datas == null || datas.size() == 0) {
                    break;
                }
                datas.clear();
            }
            // for compressed
            BigDecimal size = CompressedFilesUtil.compressedFiles(new File(e.getFileName()));
            finExportTask.setFileSize(size);
            finExportTask.setFileName(finExportTask.getFileName() + CompressedFilesUtil.FILE_STYLE);
            return Boolean.TRUE;
        }

        private boolean breakTask(FinExportTask finExportTask) {
            FinExportTask finExportTasknew = finExportTaskBo.getFinExportTask(finExportTask.getId());
            if (!BizConstant.EXPORT_TASK_STATUS_SERVICE.equals(finExportTasknew.getStatus())) {
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        }

        private void computeRemainingTime(FinExportTask finExportTask, int pageSize, Queue<Long> times, int i,
                                          long start) {
            long end = new Date().getTime();
            long time = (pageSize - i) * (end - start);
            if (times.size() > COMPUTE_TIME_TIMES) {
                times.remove();
            }
            times.add(time);
            long timeall = 0;
            for (Long lo : times) {
                timeall += lo;
            }
            time = timeall / times.size();
            finExportTask.setServiceEndDate(new Date(new Date().getTime() + time));
            finExportTaskBo.computeRemainingTime(finExportTask);
        }

        private void reviseMax(Export e) throws SQLException {
            int skip = e.getSkip();
            String action = e.getAction();
            String query = e.getQuery();
            int max = e.getMax();
            int maxTo = getDao(action).queryCount(query, e.getData());
            if (maxTo < max + skip) {
                max = maxTo - skip + 1;
                if (max < 0) {
                    max = 0;
                }
            }
            e.setMax(max);
        }

        private Queryable getDao(String dao) throws SQLException {

            Object ret = mFact.getBean(dao);
            if (ret == null) {
                throw new SQLException("Dao bean [" + dao + "] not found.");
            }
            if (!(ret instanceof Queryable)) {
                throw new SQLException("Dao bean [" + dao + "] must implements com.ali.shy.dao.Queryable.");
            }
            return (Queryable) ret;
        }

        private final class Export {

            public String getFileName() {
                return fileName;
            }

            public void setFileName(String fileName) {
                this.fileName = fileName;
            }

            public String getAction() {
                return action;
            }

            public void setAction(String action) {
                this.action = action;
            }

            public String getQuery() {
                return query;
            }

            public void setQuery(String query) {
                this.query = query;
            }

            public int getSkip() {
                return skip;
            }

            public void setSkip(int skip) {
                this.skip = skip;
            }

            public int getMax() {
                return max;
            }

            public void setMax(int max) {
                this.max = max;
            }

            private String fileName;
            private String action;
            private String query;
            private int    skip;
            private int    max;

            public Map<String, Object> getData() {
                return data;
            }

            public void setData(Map<String, Object> data) {
                this.data = data;
            }

            private Map<String, Object> data;
        }
    }
}

發佈了76 篇原創文章 · 獲贊 109 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章