Statement和PreparedStatement的區別
聯繫
- PreparedStatement繼承自Statement,兩者都是接口。
- Statement 用於執行靜態SQL 語句在執行時,必須指定一個事先準備好的SQL語句。
- PreparedStatement 是預編譯的SQL語句對象,sql語句被預編譯並保存在對象中。被封裝的sql語句代表某一類操作,語句可以包含動態的參數 “ ?”,執行時可以爲“ ? ”動態設置參數值。
- 使用PreparedStatement對象執行sql時,sql語句被數據庫進行解析和編譯,然後被放到命令緩存區,每當執行同一個PreparedStatement 對象時,它就會被解析一次,但不會被再次編譯。在緩存區可以發現預編譯的sql命令,並且可以重用。
- PreparedStatement 可以減少編譯次數提高數據庫性能。
防止SQL注入
方法一:創建Statement對象
例如:
1.Class.forName(com.mysql.jdbc.Driver);//加載驅動
2.Connection conn=DriverManager.getConnection("jdbc:mysql//:....")//創建與某個數據庫的連接
3.Statement stmt=conn.CreateStatement();//創建一個statementd對象
4.String id=01;
5.String sql="delete from table where id='"+id+"'";//構建SQL語句
6.stmt.executeUpdate(sql);//執行SQL語句
上面的這段代碼的本意是想刪除在數據庫裏刪除 id=01 的記錄,但是如果有人將 id 的內容改爲 " 01 or 1=1" 時,數據庫在接收到命令後,無論你輸入是否存在都會執行,因爲數據庫會把 " or 1=1"當成判斷條件,所以無論如何該語句都會執行。那麼表中的任何記錄都將被刪除,後果會非常嚴重。
缺點:
- 不能防止sql 注入,安全性低
- 每次執行都需要重新編譯sql語句,效率低下。
方法二:創建PreparedStatement對象
1.Class.forName(com.mysql.jdbc.Driver);//加載驅動
2.Connection conn=DriverManager.getConnection("jdbc:mysql//:....")//創建與某個數據庫的連接
3.String sql="delete from table where id=?";//構建SQL語句,設置佔位符
4.PreparedStatement ps=conn.PreparedStatement(sql);//創建PreparedStatement時傳入sql語句,實現預編譯
5.ps.setInt(1,"01");//設置sql語句的佔位符的值,注意第一個參數爲1
6.ps.executeUpdate();//執行SQL語句
爲什麼PreparedStatement能防止sql注入呢???
因爲sql 語句是預編譯的,而且語句中使用了佔位符,規定了sql語句的結構。並且如果輸入" 01 or 1=1"時,數據庫會把" 01 or 1=1"當成值,而不是"1=1" 當成判斷條件,所以能防止sql注入。
實際開發中,建議使用PreparedStatement訪問數據庫,因爲它不僅能防止sql注入,安全性提高;而且是預編譯的 ,不用每執行一次都需要重新編譯SQL語句,效率高;另外,它執行語句得到的結果是離線的,連接關閉後,仍然可以訪問結果集。