首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

[JAVA100例] 第54例:JDBC PreparedStatement 預處理語句——參數化查詢與防注入

     編輯:Java 相關知識

本例演示封裝 PreparedStatement 通用執行器:自動綁定參數、區分查詢與 DML、結果集映射為 Vector、資源自動管理。

核心代碼結構

public class StatementConn {
  private static String url, username, password;
  Connection con = null;
  PreparedStatement updStmt = null;

  public Connection conn() { ... }  // 獲取連接

  public void close() { try { con.close(); } catch (Throwable e) {} con = null; }

  // 參數綁定核心
  private PreparedStatement getStatement(String sql, Vector vCondition) throws SQLException {
    int i = 0; Object temp;
    updStmt = conn().prepareStatement(sql);
    for (i = 0; i < vCondition.size(); i++) {
      temp = vCondition.elementAt(i);
      if (temp instanceof Integer) updStmt.setInt(i+1, ((Integer)temp).intValue());
      else if (temp instanceof Double) updStmt.setDouble(i+1, ((Double)temp).doubleValue());
      else if (temp instanceof String) updStmt.setString(i+1, temp.toString().trim());
      else updStmt.setObject(i+1, temp);
    }
    return updStmt;
  }

  private void closeUpdStmt() { try { if (updStmt != null) updStmt.close(); } catch (Throwable e) {} updStmt = null; }

  // 統一執行入口
  public Object execute(String sql, Vector vCondition) throws SQLException, Exception {
    ResultSet rs = null; Vector vResult = null;
    try {
      if (!isSelect(sql)) {  // DML
        Integer iResult = new Integer(getStatement(sql, vCondition).executeUpdate());
        return iResult;
      } else {  // SELECT
        rs = getStatement(sql, vCondition).executeQuery();
        int columnCount = rs.getMetaData().getColumnCount();
        vResult = new Vector();
        while (rs.next()) {
          Vector vTemp = new Vector();
          for (int i = 0; i < columnCount; i++) {
            String sTemp = rs.getString(i+1);
            vTemp.addElement(sTemp == null ? "" : sTemp.trim());
          }
          vResult.addElement(vTemp);
        }
        rs.close(); closeUpdStmt();
      }
    } catch (Exception e1) { throw e1; }
    finally { close(); }
    return vResult;
  }

  protected boolean isSelect(String psql) {
    String sql = psql.trim().toUpperCase();
    return sql.indexOf("SELECT") == 0;
  }

  public static void main(String[] arg) { ... }
  public static void demo() {
    StatementConn oc = new StatementConn();
    String sql = "select * from TBL_USER where id > ?";
    Vector vCondition = new Vector();
    vCondition.addElement(new Integer(3));
    Vector vResult = (Vector) oc.execute(sql, vCondition);
    for (int i = 0; i < vResult.size(); i++) System.out.println(vResult.elementAt(i));
  }
}

PreparedStatement 核心優勢

優勢說明
防 SQL 注入參數化綁定,數據與代碼分離,徹底消除拼接注入風險
性能優化預編譯緩存执行計劃,重複執行無需再次解析優化
類型安全setXxx() 強類型綁定,避免隱式轉換錯誤
可讀性SQL 模板與參數分離,複雜查詢更清晰
批量處理addBatch()/executeBatch() 大幅提升批量寫入吞吐

參數綁定方法對照表

Java 類型setXxx 方法JDBC 類型
StringsetStringVARCHAR/CHAR
int/IntegersetIntINTEGER
long/LongsetLongBIGINT
double/DoublesetDoubleDOUBLE
float/FloatsetFloatREAL
boolean/BooleansetBooleanBIT/BOOLEAN
byte[]setBytesBLOB/VARBINARY
Date/Time/TimestampsetDate/setTime/setTimestampDATE/TIME/TIMESTAMP
BigDecimalsetBigDecimalDECIMAL/NUMERIC
InputStream/ReadersetBinaryStream/setCharacterStreamBLOB/CLOB
任意對象setObject驅動自動映射

代碼改進建議

  1. 使用 try-with-resources (Java 7+) 自動關閉連接/語句/結果集
  2. 泛型化返回類型:List<Map<String,Object>> 替代 Vector
  3. 區分數據源:注入 DataSource 替代硬編碼連接參數
  4. 支援命名參數:引入 Spring JdbcTemplate 或 MyBatis
  5. 異常轉換:包裝為業務異常,避免 SQLException 外洩

現代最佳實踐:JdbcTemplate

@Repository
public class UserDao {
  @Autowired JdbcTemplate jdbcTemplate;

  public List findByIdGreaterThan(int id) {
    return jdbcTemplate.query(
      "SELECT * FROM TBL_USER WHERE id > ?",
      new Object[]{id},
      (rs, rowNum) -> new User(rs.getInt("id"), rs.getString("name"), ...)
    );
  }
}

Spring JdbcTemplate 封裝了連接管理、參數綁定、結果映射、異常轉換,生產環境強烈推薦。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved