java web分页思想很常用,本质思想是:由于数据量太大,一页显示不完的,所以需要分页显示。那么分页核心就是如何计算每一页的起始下标。
分页思想总结起来就是分批次处理,除了用在web页面的分页,还适用于数据库入库和多线程操作等应用场景。
只要掌握了其原理,便可举一反三。
解析开始:
1.总共有 len 条数据,但每次只能处理 batchSize 条记录,所以需要分为 times 次来处理。
a.如果能整除比较简单:
times = len / batchSize
b.如果不能整除,只需要把余数单独作为一轮来处理就行了:
if(len%batchSize != 0) //如果不能整除,则要多跑一轮
times++;
/哈哈分割线/
2.当把批次确定好了之后,接下来计算每一轮的起始和结束下标即可。
//以len=32,batchSize=10,times=(32/10)+1=4 为例
(PS粗心的同学:整型数据相除舍去小数位,只取整数据位)
那么第一轮:[0 --9]
第二轮:[10 -- 19] //个位数是不是很规律:-)
第三轮:[20 --29]
第四轮:[30 -- 31]
或者:
第一轮:[1 -- 10]
第二轮:[11 --20] //个位数是不是很规律:-)
第三轮:[21 --30]
第四轮:[31 -- 32]
/哈哈分割线/
so,下面上代码:
a.下标从0开始计算的情况
for(int i=1; i<=times; i++)
{
start= (i-1)*batchSize; //=0, 10, 20, 30
end= start + batchSize; //=10 ,20, 30, 32
if(end>=len) //最后一轮数据未满,所以end 要特殊处理
end= len;
//这个是开区间[start,end),这个区间内的数据就是本轮要处理的数据
do something(start,end)//传入区间参数,调用函数完成计算
}
b.下标从1开始计算的情况
for(int i=1; i<=times; i++)
{
start= (i-1)*batchSize+1; //=1 ,11, 21,31
end= start + batchSize-1; //=10, 20,30,32
if(end>=len) //最后一轮数据未满,所以end 要特殊处理
end= len;
//这个是闭区间[start,end],这个区间内的数据就是本轮要处理的数据
do something(start,end)//传入区间参数,调用函数完成计算
}
下面贴上源代码:
a.下标从0开始计算的情况
/**
* 利用分页思想, 分批次入库
* @Title: batchWriteDB
* @param list list表数据过大,需要分批入库
* @param batchSize 每轮入库数据量
* @param sp spark api
* @param tbName 表名
* @param beanClass 表的bean对象
*/
public static <T> void batchWriteDB(List<T> list,int batchSize,SparkApi sp, String tbName, Class<T> beanClass)
{
int len = list.size();//总数
int times = len/batchSize;//轮数
if(len%batchSize != 0)//如果不能整除,则要多跑一轮
times++;
Log.log("-----总共"+len+" 条记录总需要分为"+times+" 轮来入库,每轮写入"+batchSize+" 条记录");
int start = 1;
int end = 1;
for(int i=1;i<=times; i++)
{
start = (i-1)*batchSize;
end = start + batchSize;
if(end>=len)//最后一轮数据未满
end = len;
//子集为开区间[0,len) =[0, len-1]
List<T> list2 = list.subList(start,end);
Log.log("第"+i+"轮入库:list2.size()= "+list2.size()+", list.size()="+list.size());
Log.log("start="+start+", end="+end+" length="+(end-start));
Dataset<Row> squaresDF = sp.createDataFrame(list2, beanClass);
squaresDF.coalesce(Config.nSparkCores).write().partitionBy("timeh").mode(SaveMode.Append).saveAsTable(tbName);
squaresDF = null;
}
}
b.下标从1开始计算的情况
public static void hbaseMultiInsert(int dataNum,int ThreadNum) throws InterruptedException
{
if(dataNum%ThreadNum!=0)//如果不能整除,则要多跑一轮
ThreadNum ++;
int pageSize = dataNum/ThreadNum;//分页思想:每轮执行多少数据
int start = 1;
int end = 1;
//同步器
final CountDownLatch cdl = new CountDownLatch(ThreadNum);
long starttime=System.currentTimeMillis();
for(int k=1;k<=ThreadNum;k++)
{
start = (k-1)*pageSize+1;
end = start+pageSize-1;
if(end>=dataNum)//最后一轮数据未满
end = dataNum;
//extends Thread这样调用
new MyThread(cdl,start,end).start();
/*
//MyThread implements Runnable这样调用
MyThread my = new MyThread(start,end);
Thread thread = new Thread(my);
thread.start();
*/
}
try {
cdl.await();
long spendtime=System.currentTimeMillis()-starttime;
System.out.println( ThreadNum+"个线程花费时间:"+spendtime/1000.0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}//hbaseMultiInsert