最近對海量資料分析突然來了興趣,加上之前公司有分庫的需求,就想用多線程解決資料查詢結果集合并問題。
在海量資料的情況下,簡單的表分區已經沒有辦法滿足資料表操作需求,這個時候就需要用到資料庫分表或者分庫。分表和分庫能夠極大減輕資料庫或者表的壓力,但是資料查詢的時候就比較麻煩,需要分別取對應表或者資料庫的資料,那麼有沒有辦法實現資料庫合并呢。多線程查詢是一個既能提高執行效率又能擷取結果集的方法。 首先建立資料庫連接公用類:
package com.threadExecutor;import sun.applet.Main;import java.sql.*;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/*** Created by jimmy on 2014/10/26.*/public class NormalJDBC { private Connection connection; private PreparedStatement ps; private ResultSet resultSet; public Connection getConnection(){ try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","test","test"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return connection; } public List<Map> getQuery(String tableName){ List<Map> list = new ArrayList<>(); String sql = "select id,name,salary from "+tableName+""; connection = getConnection(); try { ps = connection.prepareCall(sql); resultSet = ps.executeQuery(); while (resultSet.next()){ Map map = new HashMap<>(); map.put("id",resultSet.getInt(1)); map.put("name",resultSet.getString(2)); map.put("salary",resultSet.getInt(3)); list.add(map); } close(connection,ps,resultSet); //Thread.sleep(1000); } catch (SQLException e) { e.printStackTrace(); close(connection,ps,resultSet); } /*catch (InterruptedException e) { e.printStackTrace(); }*/ return list; } public void close(Connection conn,PreparedStatement ps,ResultSet rs){ try { if(ps!=null){ ps.close(); ps=null; } if(rs!=null){ rs.close(); rs=null; } if(conn!=null){ conn.close(); conn=null; } }catch (SQLException e){ e.printStackTrace(); } }}然後編寫線程處理類,這裡使用到的是帶返回參數的線程:
package com.threadExecutor;import java.util.ArrayList;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.CountDownLatch;/*** Created by jimmy on 2014/10/26.*/public class NewJDBCThread implements Callable<List>{ private List list=new ArrayList<>(); private String tableName; private CountDownLatch latch;//子線程執行完畢之後主線程在執行,現在不適用這方法 public NewJDBCThread(String tableName,CountDownLatch latch){ this.tableName = tableName; this.latch = latch; } public NewJDBCThread(String tableName){ this.tableName = tableName; } @Override public List call() { NormalJDBC normalJDBC = new NormalJDBC(); List list1 = normalJDBC.getQuery(this.tableName); System.out.println(Thread.currentThread().getName()+" "+list1.size()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //latch.countDown();// return list1; } public List getList(){ return this.list; }}主線程:
package com.threadExecutor;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/*** Created by jimmy on 2014/10/26.*/public class MergeResult { public static void main(String[] args) throws InterruptedException, ExecutionException { long start = System.currentTimeMillis(); List list = new ArrayList<>(); //線程池初始化 ExecutorService executor=(ExecutorService) Executors.newCachedThreadPool(); //建立工作清單 List<NewJDBCThread> threads = new ArrayList<>(); //初始化工作清單 for(int i=1;i<5;i++){ threads.add(new NewJDBCThread("test"+i)); } List<Future<List>> results = null;//接受處理返回的結果集 //執行線程處理 results = executor.invokeAll(threads); //擷取結果集 for(Future<List> future:results){ list.addAll((List)future.get());//講線程傳回值轉為list並加入到主線程結果集中 } System.out.println("執行時間:"+(System.currentTimeMillis()-start)+" 資料量"+list.size()); }}
經過測試,這裡因為線程休眠,如果單線程執行的話,4個線程需要4400多毫秒,資料庫執行400多毫秒,但是通過多線程的話只需要1400多毫秒,也就是一條執行的時間。因此是證實多線程執行是符合要求的。 第一次寫部落格,歡迎拍磚。更加歡迎指點。