2013-02-24 33 views
1

我正在一個項目中處理不同模式的不同數據庫中的兩個表。因此,這意味着我有這兩個表的兩種不同的連接參數使用JDBC-通過隨機選取表執行SELECT sql

連接

我們下面假設是config.property文件 -

TABLES: table1 table2 

#For Table1 
table1.url: jdbc:mysql://localhost:3306/garden 
table1.user: gardener 
table1.password: shavel 
table1.driver: jdbc-driver 
table1.percentage: 80 



#For Table2 
table2.url: jdbc:mysql://otherhost:3306/forest 
table2.user: forester 
table2.password: axe 
table2.driver: jdbc-driver 
table2.percentage: 20 

下面的方法將讀取上述config.property file,併爲每一個ReadTableConnectionInfo object表。

private static HashMap<String, ReadTableConnectionInfo> tableList = new HashMap<String, ReadTableConnectionInfo>(); 

private static void readPropertyFile() throws IOException { 

    prop.load(Read.class.getClassLoader().getResourceAsStream("config.properties")); 

    tableNames = Arrays.asList(prop.getProperty("TABLES").split(" ")); 

    for (String arg : tableNames) { 

     ReadTableConnectionInfo ci = new ReadTableConnectionInfo(); 

     String url = prop.getProperty(arg + ".url"); 
     String user = prop.getProperty(arg + ".user"); 
     String password = prop.getProperty(arg + ".password"); 
     String driver = prop.getProperty(arg + ".driver"); 
     double percentage = Double.parseDouble(prop.getProperty(arg + ".percentage")); 

     ci.setUrl(url); 
     ci.setUser(user); 
     ci.setPassword(password); 
     ci.setDriver(driver); 
     ci.setPercentage(percentage); 

     tableList.put(arg, ci); 
    } 

} 

下面是ReadTableConnectionInfo類,將持有的所有特定表的表連接信息。

public class ReadTableConnectionInfo { 

    public String url; 
    public String user; 
    public String password; 
    public String driver; 
    public String percentage; 

    public String getUrl() { 
     return url; 
    } 

    public void setUrl(String url) { 
     this.url = url; 
    } 

    public String getUser() { 
     return user; 
    } 

    public void setUser(String user) { 
     this.user = user; 
    } 

    public String getPassword() { 
     return password; 
    } 

    public void setPassword(String password) { 
     this.password = password; 
    } 

    public String getDriver() { 
     return driver; 
    } 

    public void setDriver(String driver) { 
     this.driver = driver; 
    } 

    public double getPercentage() { 
     return percentage; 
    } 

    public void setPercentage(double percentage) { 
     this.percentage = percentage; 
    } 
} 

現在我對線程的指定數量創造的ExecutorService,並把該tableList object來構造的ReadTask講座

 // create thread pool with given size 
     ExecutorService service = Executors.newFixedThreadPool(10); 

     for (int i = 0; i < 10; i++) { 
      service.submit(new ReadTask(tableList)); 
     } 

下面是我ReadTask實現Runnable interface其中每個線程應該做連接每個表。

​​

目前我有兩個表,這意味着每個線程都爲每個表中的兩個連接,然後用做SELECT *上取決於隨機生成數表中特定的表連接。

算法: -

  1. 生成隨機數1和100之間
  2. 如果該隨機數小於table1.getPercentage()然後選擇table1 然後用table1 statement object做出SELECT sql call該數據庫。
  3. 否則選擇table2,然後使用table2 statement object爲該數據庫生成SELECT sql call

我Question-

我有搞清楚應該如何應用上面的算法,我應該如何比較random number每個tables percentage,然後再決定我需要使用哪個表和經過艱苦的時間那算出哪個table connection and statements我需要用來做一個SELECT sql call

這意味着我需要檢查每張表的getPercentage()方法,並將它們與隨機數進行比較。

現在我只有兩張桌子,將來我可以有三張桌子,百分比分佈可能爲80 10 10

更新: -

class ReadTask implements Runnable { 

    private Connection[] dbConnection = null; 
    private ConcurrentHashMap<ReadTableConnectionInfo, Connection> tableStatement = new ConcurrentHashMap<ReadTableConnectionInfo, Connection>(); 

    public ReadTask(LinkedHashMap<String, XMPReadTableConnectionInfo> tableList) { 
     this.tableLists = tableList; 
    } 


    @Override 
    public run() { 

    int j = 0; 
    dbConnection = new Connection[tableLists.size()]; 

    //loop around the map values and make the connection list 
    for (ReadTableConnectionInfo ci : tableLists.values()) { 

    dbConnection[j] = getDBConnection(ci.getUrl(), ci.getUser(), ci.getPassword(), ci.getDriver()); 
    tableStatement.putIfAbsent(ci, dbConnection[j]); 

    j++; 
    } 

     Random random = new SecureRandom(); 

     while (< 60 minutes) { 

     double randomNumber = random.nextDouble() * 100.0; 
     ReadTableConnectionInfo table = selectRandomConnection(randomNumber); 

     for (Map.Entry<ReadTableConnectionInfo, Connection> entry : tableStatement.entrySet()) { 

      if (entry.getKey().getTableName().equals(table.getTableName())) { 

       final String id = generateRandomId(random); 
       final String selectSql = generateRandomSQL(table); 

       preparedStatement = entry.getValue().prepareCall(selectSql); 
       preparedStatement.setString(1, id); 

       rs = preparedStatement.executeQuery(); 
      } 
     } 
     } 
    } 



     private String generateRandomSQL(ReadTableConnectionInfo table) { 

     int rNumber = random.nextInt(table.getColumns().size()); 

     List<String> shuffledColumns = new ArrayList<String>(table.getColumns()); 
     Collections.shuffle(shuffledColumns); 

     String columnsList = ""; 

     for (int i = 0; i < rNumber; i++) { 
      columnsList += ("," + shuffledColumns.get(i)); 
     } 

     final String sql = "SELECT ID" + columnsList + " from " 
       + table.getTableName() + " where id = ?"; 

     return sql; 
    } 


    private ReadTableConnectionInfo selectRandomConnection(double randomNumber) { 

     double limit = 0; 
     for (ReadTableConnectionInfo ci : tableLists.values()) { 
      limit += ci.getPercentage(); 
      if (random.nextDouble() < limit) { 
       return ci; 
      } 
      throw new IllegalStateException(); 
     } 
     return null; 
    } 
    } 

回答

1

你可以把它作爲一個循環在可用的連接,類似如下:

public run() { 
    ... 
    Random random = new SecureRandom(); 

    while (< 60 minutes) { 
    double randomNumber = random.nextDouble() * 100.0; 
    ReadTableConnectionInfo tableInfo = selectRandomConnection(randomNumber); 

    // do query... 
    } 
} 


private ReadTableConnectionInfo selectRandomConnection(double randomNumber) { 
    double limit = 0; 
    for (ReadTableConnectionInfo ci : tableLists.values()) { 
    limit += ci.getPercentage(); 
    if (randomNumber < limit) { 
     return ci; 
    } 
    throw new IllegalStateException(); 
} 

只要randomNumber的最大值小於sum(百分比),那就可以完成這項工作。

我想到的另外一件事情是:如果您最終會遇到如此多的可能的查詢以至於循環查找成爲問題,那麼您可以構建一個查找表:創建一個數組,使得數組包含足夠的條目,以便查詢的相對權重可以用整數表示。

對於三個查詢(80:10:10)的示例,有一個10條目數組ReadTableConnectionInfo,其中八個引用指向table1,一個指向table2,另一個指向table3。然後簡單地擴展您的隨機數是0 <= rand < 10(如(int)(Math.random() * 10),並在你的陣列用它來索引

+0

感謝sharakan的建議。我只是通過稍微修改代碼來更新我的問題。讓我知道這也不錯。關於你的查詢表。我會試着看看它是否成爲瓶頸。 – AKIWEB 2013-02-24 04:47:53

+0

不,那不行。 1)nextRandom()每次調用它時會生成一個新的隨機數。 2)nextRandom()從[0..1]返回一個數字,如果'limit'的值將從[0..100]開始,則需要對其進行縮放。3)您應該創建一次Random對象,然後重複使用它,不要每次都重新創建它。看看javadocs:http://docs.oracle.com/javase/6/docs/api/java/util/Random.html#nextDouble() – sharakan 2013-02-24 04:52:26

+0

我想我對你發佈代碼的方式感到困惑。你能在你的代碼中告訴我你從哪裏得到randomNumber值嗎?如果您可以在我的代碼中提供基於代碼的實際流程,這也將非常有幫助。然後我可以正確理解流程。提前致謝。 – AKIWEB 2013-02-24 04:55:57

0

不管你有多少表,他們的百分比總是加起來100最簡單的方式概念化,你會如何選擇是代表認爲每個表一系列的百分比。

例如,對於有你提到的百分比(80%,10%,10%),三個表,你可以概念化他們爲:

隨機數 來自至== ==表0.0000 0.8000 TABLE_1 0.8000 0.9000 TABLE_2 0.9000 1.0000 TABLE_3

所以,產生0.0000和1.0000之間,然後隨機#下井有序列表,看看哪些範圍配合,因此要使用的表。

(順便說一句:我不知道爲什麼你必須爲每個表連接。)

+0

比ks大流士。無論你發佈什麼,我已經知道,就像我需要生成隨機數等等等等。唯一的事情我無法理解如何使所有這些東西在代碼中一起工作。關於你爲什麼每個表有兩個連接的問題。因爲通過隨機數字生成,可能我需要在Table1或Table2上工作,所以我需要在這些表格的基礎上選擇選擇哪個表格,這就是兩個連接的原因。 – AKIWEB 2013-02-24 04:30:49

0

你可以建立包含表名和其重量的查找表:

class LookupTable { 
    private int[] weights; 
    private String[] tables; 
    private int  size = 0; 

    public LookupTable(int n) { 
     this.weights = new int[n]; 
     this.tables = new String[n]; 
    } 

    public void addTable(String tableName, int r) { 
     this.weights[size] = r; 
     this.tables[size] = tableName; 
     size++; 
    } 

    public String lookupTable(int n) { 
     for (int i = 0; i < this.size; i++) { 
      if (this.weights[i] >= n) { 
       return this.tables[i]; 
      } 
     } 
     return null; 
    } 
} 

的代碼來初始化該表:

LookupTable tr = new LookupTable(3); 
    // make sure adds the range from lower to upper! 
    tr.addTable("table1", 20); 
    tr.addTable("table2", 80); 
    tr.addTable("table3", 100); 

測試代碼:

Random r = new Random(System.currentTimeMillis()); 
    for (int i = 0; i < 10; i++) { 
     // r.nextInt(101) + 1 would return a number of range [1~100]. 
     int n = r.nextInt(101) + 1; 
     String tableName = tr.lookupTable(n); 
     System.out.println(n + ":" + tableName); 
    } 
+0

感謝ericson的幫助。在我的代碼中,我已經有了'ReadTableConnectionInfo'類,它將包含表信息及其百分比(權重),因此創建另一個類將使我有很多重複的代碼。 – AKIWEB 2013-02-24 05:06:52