JDBC PreparedStatement 批量查詢 in 的實現 方案

咱們常常會有這種業務需求,根據一個條件集合去查詢一張表的數據,好比:
select * from tablename t where t.name in (List <taskids>);
在java語言中,咱們須要用到JDBC來和數據庫打交道,那麼在JDBC中該如何處理這種需求呢?咱們能夠有以下幾種處理方式java

方案一:寫一個函數把參數集合轉換成一個or 條件 或 in 條件的字符串,最後拼成一個sql算法

select from tablename t where t.name in ('123' ,'456', '789');
或者是:
select
from tablename t where t.name='123' or t.name= '456' t.name= '789';sql

可是這樣效率如何呢?咱們知道Oracle對傳過來的SQL是須要事先編譯的,不過是Oracle有個緩存功能能夠緩存編譯好的SQL,但前提是傳過來的SQL必須徹底一致,很明顯,若是按照以上方式的話,一旦taskid值變化,那麼Oracle的緩存便沒法利用。

方案二:使用預編譯的PrepareStatement數據庫

爲了解決Oracle緩存沒法利用問題,Jdbc提供了預編譯的PrepareStatement,對於變化的參數能夠用佔位符 <?> 來代替,所以咱們能夠用佔位符來減小Oracle編譯次數。
    private static final String QUERY = "select * from tablename where name= ?";
      ps = con .prepareStatement(QUERY);
      for(String name : taskIds){
         ps.setString(1,name);
         rs = ps .executeQuery();
      }
這樣作雖然能夠很好的利用Oracle的緩存,但缺點也很明顯,就是每個Id都須要查詢數據庫一次,這樣效率是極低的。

方案三:動態地建立PrepareStatement緩存

雖然變化的參數能夠用佔位符 <?> 來代替,然而遺憾的是Jdbc只提供了單一佔位符功能即佔位符不能是一個可迭代的集合。所以,對於咱們傳過來的集合參數,咱們能夠動態地建立一個PrepareStatement:

拼一個和集合大小相等數量佔位符的SQL,再寫一個循環來賦值每個佔位符,這樣就能夠解決taskId的值變化而致使Oracle從新編譯SQL問題。
private static void createQuery(List<String> taskIds) {
      String query = "select * from tablename t where t.name in (";
      StringBuilder queryBuilder = new StringBuilder(query);
       for ( int i = 0; i < taskIds.size(); i++) {
          queryBuilder.append( " ?");
           if (i != taskIds.size() - 1)
               queryBuilder.append( ",");
      }
      queryBuilder.append( ")");
       ps = con .prepareStatement(query);
       for ( int i = 1; i <= taskIds.size(); i++) {
           ps.setString(i, taskIds.get(i - 1).toString());
      }
       rs = ps .executeQuery();
 }
可是這麼作仍是存在一個問題,若是集合的值變化不會致使Oracle從新編譯,可是若是集合的大小發生變化,相對應的SQL也就發生了變化,一樣也會致使Oracle從新編譯,那麼該如何解決這個問題呢?

方案四:批量查詢(減小查詢次數並利用到Oracle緩存)app

批量查詢兼顧了第2、第三種方案,其思想是預先定義好幾個每次要查詢參數的個數,而後把參數集合按這些定義好的值劃分紅小組。好比咱們的前臺傳過來一個數量爲75的taskId的集合,我預約義的批量查詢參數的個數分別爲:
SINGLE_BATCH = 1;//注意:爲了把參數集合完整劃分,這個值爲1的批量數是必須的
SMALL_BATCH = 4;
MEDIUM_BATCH = 11;
LARGE_BATCH = 51;

那麼咱們第一次會查詢51條數據,還剩下24個沒有查詢,那麼第二次批量查詢11條數據,還剩下13條未查詢,第三次再批量查詢11條數據,最後還剩2條未查詢,那麼咱們再分兩批次,每批次僅查詢一條,這樣,最終一個75條的數據分5批次便可查詢完成,減小了查詢次數,並且還利用到了數據庫緩存。附獲取批量的算法:
 public static final int SINGLE_BATCH = 1; //注意:爲了把參數集合完整劃分,這個值爲1的批量數是必須的
  public static final int SMALL_BATCH = 4;
  public static final int MEDIUM_BATCH = 11;
  public static final int LARGE_BATCH = 51;
  static int totalNumberOfValuesLeftToBatch=75;
  public static List<Integer>  getBatchSize( int totalNumberOfValuesLeftToBatch){
      List<Integer> batches= new ArrayList<Integer>();
       while ( totalNumberOfValuesLeftToBatch > 0 ) {
           int batchSize = SINGLE_BATCH;
           if ( totalNumberOfValuesLeftToBatch >= LARGE_BATCH ) {
            batchSize = LARGE_BATCH;
          } else if ( totalNumberOfValuesLeftToBatch >= MEDIUM_BATCH ) {
            batchSize = MEDIUM_BATCH;
          } else if ( totalNumberOfValuesLeftToBatch >= SMALL_BATCH ) {
            batchSize = SMALL_BATCH;
          }
          batches.add(batchSize);
          totalNumberOfValuesLeftToBatch -= batchSize;
          System. out.println(batchSize);
      }
       return batches;
 }
相關文章
相關標籤/搜索