Java分頁思想在分批次入庫和多線程操作中的應用

    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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章