程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> 通過jdbc使用PreparedStatement,提升性能,防止sql注入,preparedstatement

通過jdbc使用PreparedStatement,提升性能,防止sql注入,preparedstatement

編輯:MySQL綜合教程

通過jdbc使用PreparedStatement,提升性能,防止sql注入,preparedstatement


為什麼要使用PreparedStatement?

一、通過PreparedStatement提升性能

     Statement主要用於執行靜態SQL語句,即內容固定不變的SQL語句。Statement每執行一次都要對傳入的SQL語句編譯一次,效率較差。
     某些情況下,SQL語句只是其中的參數有所不同,其余子句完全相同,適用於PreparedStatement。
PreparedStatement的另外一個好處就是預防sql注入攻擊
     PreparedStatement是接口,繼承自Statement接口。
    使用PreparedStatement時,SQL語句已提前編譯,三種常用方法 execute、 executeQuery 和 executeUpdate 已被更改,以使之不再需要參數。
     PreparedStatement 實例包含已事先編譯的 SQL 語句,SQL 語句可有一個或多個 IN 參數,IN參數的值在 SQL 語句創建時未被指定。該語句為每個 IN 參數保留一個問號(“?”)作為占位符。
     每個問號的值必須在該語句執行之前,通過適當的setInt或者setString 等方法提供。
     由於 PreparedStatement 對象已預編譯過,所以其執行速度要快於 Statement 對象。因此,多次執行的 SQL 語句經常創建為 PreparedStatement 對象,以提高效率。
通常批量處理時使用PreparedStatement。
  

 

1 //SQL語句已發送給數據庫,並編譯好為執行作好准備
2 PreparedStatement pstmt = con.prepareStatement(
3          "UPDATE  emp   SET job= ? WHERE empno = ?");
4 //對占位符進行初始化 
5 pstmt.setLong(1, "Manager");
6 pstmt.setInt(2,1001);
7 //執行SQL語句
8 pstmt.executeUpdate();

 

小案例:分別向數據庫插入1000條記錄。分別記錄執行時間,然後進行比較。

 

新建項目:

 

使用Statement的 執行效率的類INSERT3:

 1 package com.cnblogs.daliu_it;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.Statement;
 6 
 7 /**
 8  * 使用Statement的 執行效率
 9  * 
10  */
11 public class INSERT3 {
12 
13     public static void main(String[] args) {
14         Connection conn = null;
15         try {
16             conn = DBUtility.getConnection();
17             Statement state = conn.createStatement();
18             long start = System.currentTimeMillis();
19 
20             for (int i = 7000; i < 8000; i++) {
21                 String sql = "INSERT INTO user VALUES" + "(" + i + ","
22                         + "'test" + i + "'," + "'12345'," + "5000," + "'test"
23                         + i + "@qq.com'" + ")";
24                 state.executeUpdate(sql);
25             }
26             System.out.println("插入完畢");
27             long end = System.currentTimeMillis();
28             System.out.println("耗時:" + (end - start));
29         } catch (Exception e) {
30             System.out.println("插入數據失敗");
31             e.printStackTrace();
32         } finally {
33             DBUtility.closeConnection(conn);
34         }
35     }
36 }

 

測試數據:

 

使用預編譯PreparedStatement SQL提高執行效率的類INSERT2:

 1 package com.cnblogs.daliu_it;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 
 6 /**
 7  * 使用預編譯PreparedStatement SQL提高執行效率
 8  * 
 9  */
10 public class INSERT2 {
11     public static void main(String[] args) {
12         Connection conn = null;
13         try {
14             conn = DBUtility.getConnection();
15             // Statement state= conn.createStatement();
16 
17             String sql = "INSERT INTO user VALUES(?,?,'123456',?,?)";
18             /*
19              * 根據給定的預編譯SQL語句創建一個 PreparedStatement
20              */
21             PreparedStatement ps = conn.prepareStatement(sql);
22 
23             long start = System.currentTimeMillis();
24 
25             for (int i = 9000; i < 10000; i++) {
26                 ps.setInt(1, i);
27                 ps.setString(2, "test" + i);
28                 ps.setInt(3, 5000);
29                 ps.setString(4, "test" + i + "@qq.com");
30                 ps.executeUpdate();
31             }
32             System.out.println("插入完畢");
33             long end = System.currentTimeMillis();
34             System.out.println("耗時:" + (end - start));
35         } catch (Exception e) {
36             System.out.println("插入數據失敗");
37             e.printStackTrace();
38         } finally {
39             DBUtility.closeConnection(conn);
40         }
41     }
42 }

 

測試效果:



二、通過PreparedStatement防止SQL Injection

      對JDBC而言,SQL注入攻擊只對Statement有效,對PreparedStatement無效,因為PreparedStatement不允許在插入參數時改變SQL語句的邏輯結構。
      使用預編譯的語句對象時,用戶傳入的任何數據不會和原SQL語句發生匹配關系,無需對輸入的數據做過濾。如果用戶將”or 1 = 1”傳入賦值給占位符,下述SQL語句將無法執行:select * from t where username = ? and password = ?;

      PreparedStatement是Statement的子類,表示預編譯的SQL語句的對象。在使用PreparedStatement對象執行SQL命令時,命令被數據庫編譯和解析,並放入命令緩沖區。緩沖區中的預編譯SQL命令可以重復使用。

 1  sql = "select * from users where NAME = ? and PWD = ?";
 2    System.out.println(sql);
 3 
 4   
 5    con = DBUtility.getConnection();
 6 
 7    //通過Statement 的改為prepareStatement
 8    stmt = con.prepareStatement(sql);
 9 
10   
11 //   rs = stmt.executeQuery(sql);
12    
13     stmt.setString(1, username);
14              stmt.setString(2, password);
15              rs = stmt.executeQuery();

 


使用PreparedStatement來執行SQL語句。在SQL語句中有2個問號,在代碼中要給它們分別設置值,規則是:從左到右,對應1,2,...。

對於JDBC而言,SQL注入攻擊只對Statement有效,對PreparedStatement是無效的,這是因為PreparedStatement不允許在插入時改變查詢的邏輯結構。

 

 


 例子:使用PreparedStatement實現用戶名和密碼的驗證功能。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved