DB2 SQL statement too long or complex.

前景:DB2数据库、Mybatis、数据插入。

也不知道这样做合不合理。欢迎指导*.*

<insert id="batchAddPlan">
        INSERT INTO TB_POC_C_PLAN_ALLYEAR(ID,VERSIONS,YEAR,MONTH,PLAN_DATE,WEEK,WEEK_DAT,CAR_ID,ASSEMBLY,COUNT,CREATER,CREATER_DATE,NAME,VERSION_NAME) VALUES
        <foreach collection="list" item="item" index="index" separator=",">
            (NEXTVAL FOR ID_SEQ,#{item.versions},#{item.year},#{item.month},#{item.planDate},#{item.week},#{item.weekDat},NULL,NULL,#{item.count},#{username},CURRENT DATE,#{item.name},#{item.versionName})
        </foreach>
    </insert>

执行后报错:SQL statement too long or complex. (原因是ibatis动态生成的sql很长)

后来同事说可以使用多线程插入,这里没有使用继承Thread或实现Runable接口,而是使用的Callable<V>接口。

大致的思路是:

  1. 将原来的数据分割成多个子数据集合

  2. 每个子数据集合放到一个线程中执行

  3. 每个线程返回一个值:正常返回0;错误返回-1

  4. 多个线程的返回值和为0则正常,否则抛出异常,执行数据库事务。

线程类如下:

class ConCurrentDB2Insert implements Callable<Integer> {

        private List<AllYearPlan> parameters;
        private String username;

        ConCurrentDB2Insert(List<AllYearPlan> parameters, String username) {
            this.parameters = parameters;
            this.username = username;
        }

        @Override
        public Integer call() throws Exception {
            try {
                dao.batchAddPlan(this.parameters, this.username);
            } catch (Exception e) {
                e.printStackTrace();
                return -1;
            }
            return 0;
        }
    }

执行上述类的方法如下:

private boolean execute(String username, List<AllYearPlan>...args) throws Exception{
        ExecutorService exec = Executors.newCachedThreadPool();
        int sum = 0;
        List<Future<Integer>> results = new ArrayList<Future<Integer>>();
        for (int i = 0; i < args.length; i++) {
            results.add(exec.submit(new ConCurrentDB2Insert(args[i], username)));
        }

        for (Future<Integer> result: results) {
            if (result.isDone()) {
                sum += result.get();
            }
        }
        exec.shutdown();
        return sum==0?true:false;
    }

分割数据包的类如下:

/**
     * List分割类
     * @param <T>
     */
    class ListSplit<T> {

        private List<T> list;
        private int pageSize;
        private int pageCount;
        private int totalCount;
        private int m;
        private List<T>[] results;

        public ListSplit(List<T> list, int pageSize) {
            this.list = list;
            this.pageSize = pageSize;
            this.pageCount = 0;
            this.totalCount = list.size();
            this.m = totalCount%pageSize;
        }

        public List<T>[] split() {
            if  (m>0) {
                pageCount=totalCount/pageSize+1;
            } else {
                pageCount=totalCount/pageSize;
            }
            this.results = new List[pageCount];
            for(int i=1;i<=pageCount;i++){
                if (m==0) {
                    List<T> subList= list.subList((i-1)*pageSize,pageSize*(i));
                    this.results[i-1] = subList;
                } else {
                    if (i==pageCount) {
                        List<T> subList= list.subList((i-1)*pageSize,totalCount);
                        this.results[i-1] = subList;
                    } else {
                        List<T> subList= list.subList((i-1)*pageSize,pageSize*(i));
                        this.results[i-1] = subList;
                    }
                }
            }
            return this.results;
        }
    }

具体调用方法如下:

try {
            this.execute(username, new ListSplit<AllYearPlan>(parameters, 100).split());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }


你可能感兴趣的:(DB2 SQL statement too long or complex.)