<<JDBC爲何要使用PreparedStatement而不是Statement>> 列舉了爲何PreparedStatement要優於Statement,其中最主要的兩點是更快的性能和防止SQL注入攻擊。在文章的末尾提到了一個侷限性:PreparedStatement不容許一個佔位符(?)有多個值,並提出瞭如何在**IN**子句使用PreparedStatement的棘手問題。html
《JDBC PreparedStatement IN clause alternative approaches》 給出了四種方案:java
1. Execute Single Queriessql
2. Using Stored Procedureapp
3. Creating PreparedStatement Query dynamically性能
4. Using NULL in PreparedStatement Queryui
第三和第四方案看起來更合適些,第四種方案能夠看做是第三種方案的擴展。spa
第三種使用下面代碼構建SQL語句code
private static String createQuery(int length) { String query = "select empid, name from Employee where empid in ("; StringBuilder queryBuilder = new StringBuilder(query); for( int i = 0; i< length; i++){ queryBuilder.append(" ?"); if(i != length -1) queryBuilder.append(","); } queryBuilder.append(")"); return queryBuilder.toString(); }
這種方式雖然可行,可是若是輸入的參數個數發生變化,就不會get the PreparedStatement benefit of caching and reusing the execution plan。htm
因此就有了第四種方案:blog
public class JDBCPreparedStatementNULL { private static final String QUERY = "select empid, name from Employee where empid in ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final int PARAM_SIZE = 10; public static void printData(int[] ids){ if(ids.length > PARAM_SIZE){ System.out.println("Maximum input size supported is "+PARAM_SIZE); //in real life, we can write logic to execute in batches, for simplicity I am returning return; } Connection con = DBConnection.getConnection(); PreparedStatement ps = null; ResultSet rs = null; try { ps = con.prepareStatement(QUERY); int i = 1; for(; i <=ids.length; i++){ ps.setInt(i, ids[i-1]); } //set null for remaining ones for(; i<=PARAM_SIZE;i++){ ps.setNull(i, java.sql.Types.INTEGER); } rs = ps.executeQuery(); while(rs.next()){ System.out.println("Employee ID="+rs.getInt("empid")+", Name="+rs.getString("name")); } //close the resultset here try{ rs.close(); } catch(SQLException e){} } catch (SQLException e) { e.printStackTrace(); }finally{ try { ps.close(); con.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
在第三種方案的基礎上,咱們肯定最大參數個數,除了輸入的參數外,剩餘參數所有用setNull
()置爲空。這樣又能夠重用執行計劃和預處理的cache。
More:PreparedStatement and Statement能夠批量執行,參考《使用JDBC進行批處理》