2012-04-12 62 views
2

我想修改一些Java現有代碼(不是由我完成的),並且我發現查詢沒有使用prepare語句完成。 因爲我有很多代碼,我試圖儘可能少地修改它。 因此,而不是具有類似於準備語句:使用ArrayList的參數創建方法

public void executeInsertStmt(String strQuery, String param1, String param2) { 

... 
... 
PreparedStatement preparedStatement = cnx.prepareStatement(stringRequest); 
preparedStatement.setString(1, param1); 
preparedStatement.setString(2, param2); 
} 

的方法,我想那樣做的(我不知道這是最好的解決方案)。

public void executeInsertStmt(String strQuery, ArrayList<ArrayList<Object>> parameters) { 

PreparedStatement preparedStatement = cnx.prepareStatement(stringRequest); 

int counter=1; 
      for (final ArrayList<Object> eachParam : parameters) { 

       switch(DataTypes.valueOf(eachParam.get(0).toString().toUpperCase())) 
       { 
        case STRING: 
         preparedStatement.setString(counter, (String)eachParam.get(1)); 
        break; 
        case DATE: 
         preparedStatement.setDate(counter, (Date)eachParam.get(1)); 
        break; 
        case INT: 
         preparedStatement.setInt(counter, (Integer)eachParam.get(1)); 
        break; 
        default: 
         preparedStatement.setString(counter, (String)eachParam.get(1)); 
        break; 
       } 

       counter++; 

      } 
} 

再有這樣的事情:

strQuery = "insert into toto values (?,?)"; 
ArrayList<Object> paramToPass1 = new ArrayList<Object>(); 

paramToPass1.add("String"); 
paramToPass1.add("TheValueForTheString"); 

ArrayList<Object> paramToPass2 = new ArrayList<Object>(); 

paramToPass2.add("String"); 
paramToPass2.add("TheValueForTheString2"); 

ArrayList<ArrayList<Object>> paramToPass = new ArrayList<ArrayList<Object>>(); 

paramToPass.add(paramToPass1); 
paramToPass.add(paramToPass2); 


executeInsertStmt(strQuery,paramToPass); 

因爲我有不同數量的參數很多查詢這種形式給出的將是最適合我。 我不必爲每種類型的查詢做一個方法。

您怎麼看。

這是錯的嗎? 是最好的方式去?

謝謝你的任何想法。

+0

我做了類似的,但有兩個方法,1收到一個'List lstParameters'和另一個方法'List lstParameters',第一個接收到一個帶有IN參數的數組,第二個接收到一個'MyOwnSQLParatemer'對象,告訴參數的方向:IN,OUT,INOUT。 – 2012-04-12 14:16:16

+0

如果你被允許使用Spring JDBC,那將大大簡化很多這些。 – GriffeyDog 2012-04-12 14:35:54

+0

如果你還有很多工作要做,爲什麼不逐步轉向更高層次的解決方案,即使用[jOOQ](http://www.jooq.org),[DbUtils](http:// commons。 apache.org/dbutils/),[spring-data](http://www.springsource.org/spring-data),[Hibernate](http://www.hibernate.org/)等等。認爲你不應該花太多的時間來改善一些事情(可能會讓它們變得更糟) – 2012-04-12 14:56:31

回答

1

您應該爲您的參數使用對象表示形式,而不是使用大小爲2的ArrayList<Object>。此外,您不需要自己的DataType枚舉,但已經有java.sql.Types類。最重要的是,在PreparedStatement上有一個setObject()方法可以識別這些類型的值,因此您不需要switch語句或調用類型特定的PreparedStatement.set..()方法。

下面是一個解決方案,它具有參數的對象表示形式,利用了java.sql.TypespreparedStatement.setObject()對這些類型的支持,並且使您不受類型常量值的影響。

首先,對於參數對象表示:

import java.sql.Types; 

public class ParamDescriptor { 
    // Constructor itself is private, we are encapsulating so that 
    // you don't need to write java.sql.Types constants yourself 
    private ParamDescriptor(int dataType, Object value) { 
     _dataType = dataType; 
     _value = value; 
    } 

    // Factory methods for actual instantiation 
    public static ParamDescriptor forInt (int paramVal) { 
     return new ParamDescriptor (Types.INTEGER, paramVal); 
    } 

    public static ParamDescriptor forString (String paramVal) { 
     return new ParamDescriptor (Types.VARCHAR, paramVal); 
    } 

    public static ParamDescriptor forDate (Date paramVal) { 
     return new ParamDescriptor (Types.DATE, paramVal); 
    } 
    // Add more here to support more data types . . . .  


    public int getDataType() { 
     return _dataType; 
    } 

    public Object getValue() { 
     return _value; 
    } 

    private int  _dataType; 
    private Object _value; 
} 

接着,executeInsertStmt()新版本。我們已經將它降低到只有幾行,它永遠不需要再次改變,無論未來支持的參數類型:

public void executeInsertStmt(String strQuery, List<ParamDescriptor> parameters) throws SQLException {  
     PreparedStatement preparedStatement = cnx.prepareStatement(strQuery); 

     int counter = 1; 
     for (ParamDescriptor paramDescriptor : parameters) { 
      preparedStatement.setObject(counter, 
             paramDescriptor.getValue(), 
             paramDescriptor.getDataType()); 
      counter++; 
     } 
    } 

最後,代碼,將調用新的executeInsertStmt()

String strQuery = "insert into toto values (?,?)"; 

ParamDescriptor paramToPass1 = ParamDescriptor.forString("TheValueForTheString"); 
ParamDescriptor paramToPass2 = ParamDescriptor.forString("TheValueForTheString2"); 

List<ParamDescriptor> parameters = new ArrayList<ParamDescriptor>(); 
parameters.add(paramToPass1); 
parameters.add(paramToPass2); 

executeInsertStmt(strQuery, parameters); 

請注意,如果您計劃處理小數點,則會有另一個PreparedStatement.setObject()版本支持指定小數位數。您可能需要爲您的executeInsertStmt()添加某種支持。

+0

太好了。非常感謝。它更清潔你的方法。幫助我很多。 – 2012-04-12 15:34:09

+0

我的榮幸!樂意效勞。感謝恭維和接受。 – 2012-04-12 15:37:45

0

那麼,你的想法並不差...只是一些指針。

不傳遞ArrayList的ArrayList ...而是使用instanceof或DataHolder類。

方法1:的instanceof

簡單的添加類型的整數,字符串,雙等,然後在你的方法:

public void executeInsertStmt(String strQuery, ArrayList<Object> parameters) { 

    PreparedStatement preparedStatement = cnx.prepareStatement(stringRequest); 
    int counter=1; 
    for (final Object eachParam : parameters) { 
     if (eachParam instanceof String) { 
      preparedStatement.setString(counter, (String)eachParam); 
     } else if (eachParam instanceof Integer) { 
      preparedStatement.setInt(counter, (Integer)eachParam); 
     } else ... 

     counter++; 

    } 
} 

具有DataHolder的想法是,在一個領域將保持類型和另一個是實際數據。你甚至可以使用通用來使它更好。但是,在這種情況下,我會舉例說明。

+1

除了'Date'數據類型,還有'setDate','setTime','setTimestamp'方法 – 2012-04-12 14:22:08

+0

謝謝爲答案。我只是有一個愚蠢的問題:什麼是DataHolder?我沒有在jdk中看到它?這是一個定製框架? – 2012-04-12 14:31:37

+0

您必須編寫自己的類才能避免使用ArrayList中的ArrayList。就像:class DataHolder {Type type;對象數據; }在這種情況下,Type可以是一個枚舉(但它也可以使用字符串,就像您最初使用的那樣) – 2012-04-12 14:36:26