Java Statement PK PrepareStatement

PreparedStatement是用來執行SQL查詢語句的API之一,Java提供了?Statement、PreparedStatement?和?CallableStatement三種方式來執行查詢語句,其中?Statement?用于通用查詢,?PreparedStatement?用于執行參數化查詢,而?CallableStatement則是用于存儲過程。同時PreparedStatement還經常會在Java面試被提及,譬如:Statement與PreparedStatement的區別以及如何避免SQL注入式攻擊?這篇教程中我們會討論為什么要用PreparedStatement?使用PreparedStatement有什么樣的優勢?PreparedStatement又是如何避免SQL注入攻擊的?

PreparedStatement是什么?

PreparedStatement是java.sql包下面的一個接口,用來執行SQL語句查詢,通過調用connection.preparedStatement(sql)方法可以獲得PreparedStatment對象。數據庫系統會對sql語句進行預編譯處理(如果JDBC驅動支持的話),預處理語句將被預先編譯好,這條預編譯的sql查詢語句能在將來的查詢中重用,這樣一來,它比Statement對象生成的查詢速度更快。下面是一個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class PreparedStmtExample {
????public static void main(String args[]) throws SQLException {
????????Connection conn = DriverManager.getConnection("mysql:\\localhost:1520", "root", "root");
????????PreparedStatement preStatement = conn.prepareStatement("select distinct loan_type from loan where bank=?");
????????preStatement.setString(1, "Citibank");
????????ResultSet result = preStatement.executeQuery();
????????while(result.next()){
????????????System.out.println("Loan Type: " + result.getString("loan_type"));
????????}??????
????}
}
Output:
Loan Type: Personal Loan
Loan Type: Auto Loan
Loan Type: Home Loan
Loan Type: Gold Loan

這個例子中,如果還是用?PreparedStatement?做同樣的查詢,哪怕參數值不一樣,比如:”Standard Chated” 或者”HSBC”作為參數值,數據庫系統還是會去調用之前編譯器編譯好的執行語句(系統庫系統初次會對查詢語句做最大的性能優化)。默認會返回”TYPE_FORWARD_ONLY”類型的結果集(?ResultSet?),當然你也可以使用preparedstatment()的重載方法返回不同類型的結果集。

預處理語句的優勢

PreparedStatement提供了諸多好處,企業級應用開發中強烈推薦使用PreparedStatement來做SQL查詢,下面列出PreparedStatement的幾點優勢。

  1. PreparedStatement可以寫動態參數化的查詢
    用PreparedStatement你可以寫帶參數的sql查詢語句,通過使用相同的sql語句和不同的參數值來做查詢比創建一個不同的查詢語句要好,下面是一個參數化查詢:

    ?

    1
    SELECT interest_rate FROM loan WHERE loan_type=?

    現在你可以使用任何一種loan類型如:”personal loan”,”home loan” 或者”gold loan”來查詢,這個例子叫做參數化查詢,因為它可以用不同的參數調用它,這里的”?”就是參數的占位符。

  2. PreparedStatement比?Statement?更快
    使用?PreparedStatement?最重要的一點好處是它擁有更佳的性能優勢,SQL語句會預編譯在數據庫系統中。執行計劃同樣會被緩存起來,它允許數據庫做參數化查詢。使用預處理語句比普通的查詢更快,因為它做的工作更少(數據庫對SQL語句的分析,編譯,優化已經在第一次查詢前完成了)。為了減少數據庫的負載,生產環境中德JDBC代碼你應該總是使用PreparedStatement?。值得注意的一點是:為了獲得性能上的優勢,應該使用參數化sql查詢而不是字符串追加的方式。下面兩個SELECT 查詢,第一個SELECT查詢就沒有任何性能優勢。
    SQL Query 1:字符串追加形式的PreparedStatement

    ?

    1
    2
    String loanType = getLoanType();
    PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=" + loanType);

    SQL Query 2:使用參數化查詢的PreparedStatement

    1
    2
    PreparedStatement prestmt = conn.prepareStatement("select banks from loan where loan_type=?");
    prestmt.setString(1,loanType);

    第二個查詢就是正確使用PreparedStatement的查詢,它比SQL1能獲得更好的性能。

  3. PreparedStatement可以防止SQL注入式攻擊
    如果你是做Java web應用開發的,那么必須熟悉那聲名狼藉的SQL注入式攻擊。去年Sony就遭受了SQL注入攻擊,被盜用了一些Sony play station(PS機)用戶的數據。在SQL注入攻擊里,惡意用戶通過SQL元數據綁定輸入,比如:某個網站的登錄驗證SQL查詢代碼為:

    ?

    1
    strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';"

    惡意填入:

    1
    2
    userName = "1' OR '1'='1";
    passWord = "1' OR '1'='1";

    那么最終SQL語句變成了:

    1
    strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"

    因為WHERE條件恒為真,這就相當于執行:

    1
    strSQL = "SELECT * FROM users;"

    因此可以達到無賬號密碼亦可登錄網站。如果惡意用戶要是更壞一點,用戶填入:

    1
    strSQL = "SELECT * FROM users;"

    SQL語句變成了:

    1
    strSQL = "SELECT * FROM users WHERE name = 'any_value' and pw = ''; DROP TABLE users"

    這樣一來,雖然沒有登錄,但是數據表都被刪除了。

    然而使用PreparedStatement的參數化的查詢可以阻止大部分的SQL注入。在使用參數化查詢的情況下,數據庫系統(eg:MySQL)不會將參數的內容視為SQL指令的一部分來處理,而是在數據庫完成SQL指令的編譯后,才套用參數運行,因此就算參數中含有破壞性的指令,也不會被數據庫所運行。
    補充:避免SQL注入的第二種方式:
    在組合SQL字符串的時候,先對所傳入的參數做字符取代(將單引號字符取代為連續2個單引號字符,因為連續2個單引號字符在SQL數據庫中會視為字符中的一個單引號字符,譬如:

    1
    strSQL = "SELECT * FROM users WHERE name = '" + userName + "';"

    傳入字符串:

    1
    userName? = " 1' OR 1=1 "

    把userName做字符替換后變成:

    1
    userName = " 1'' OR 1=1"

    最后生成的SQL查詢語句為:

    1
    strSQL = "SELECT * FROM users WHERE name = '1'' OR 1=1'

    這樣數據庫就會去系統查找name為“1′ ‘ OR 1=1”的記錄,而避免了SQL注入。

  4. 比起凌亂的字符串追加似的查詢,PreparedStatement查詢可讀性更好、更安全。

PreparedStatement的局限性

盡管PreparedStatement非常實用,但是它仍有一定的限制。
1. 為了防止SQL注入攻擊,PreparedStatement不允許一個占位符(?)有多個值,在執行有**IN**子句查詢的時候這個問題變得棘手起來。下面這個SQL查詢使用PreparedStatement就不會返回任何結果

1
2
SELECT * FROM loan WHERE loan_type IN (?)
preparedSatement.setString(1, "'personal loan', 'home loan', 'gold loan'");

那如何解決這個問題呢?請你繼續關注本博客,下期告訴你答案。

不算總結的總結

關于PreparedStatement接口,需要重點記住的是:
1. PreparedStatement可以寫參數化查詢,比Statement能獲得更好的性能。
2. 對于PreparedStatement來說,數據庫可以使用已經編譯過及定義好的執行計劃,這種預處理語句查詢比普通的查詢運行速度更快。
3. PreparedStatement可以阻止常見的SQL注入式攻擊。
4. PreparedStatement可以寫動態查詢語句
5. PreparedStatement與java.sql.Connection對象是關聯的,一旦你關閉了connection,PreparedStatement也沒法使用了。
6. “?” 叫做占位符。
7. PreparedStatement查詢默認返回FORWARD_ONLY的ResultSet,你只能往一個方向移動結果集的游標。當然你還可以設定為其他類型的值如:”CONCUR_READ_ONLY”。
8. 不支持預編譯SQL查詢的JDBC驅動,在調用connection.prepareStatement(sql)的時候,它不會把SQL查詢語句發送給數據庫做預處理,而是等到執行查詢動作的時候(調用executeQuery()方法時)才把查詢語句發送個數據庫,這種情況和使用Statement是一樣的。
9. 占位符的索引位置從1開始而不是0,如果填入0會導致*java.sql.SQLException invalid column index*異常。所以如果PreparedStatement有兩個占位符,那么第一個參數的索引時1,第二個參數的索引是2.

以上就是為什么要使用PreparedStatement的全部理由,不過你仍然可以使用Statement對象用來做做測試。但是在生產環境下你一定要考慮使用?PreparedStatement?

轉載于:https://www.cnblogs.com/wusirAaron/p/10125756.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387761.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387761.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387761.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql在linux 下安裝

安裝環境:系統是 centos6.5 1、下載 下載地址:http://dev.mysql.com/downloads/mysql/5.6.html#downloads 下載版本:我這里選擇的5.6.33,通用版,linux下64位 也可以直接復制64位的下載地址,通過命令下載&a…

Leetcode PHP題解--D47 868. Binary Gap

2019獨角獸企業重金招聘Python工程師標準>>> D47 868. Binary Gap 題目鏈接 868. Binary Gap 題目分析 給定一個數字,計算其二進制表示中,出現的兩個1最大距離。 思路 當然是先轉換成二進制了。再進行遍歷。 當只有一個1時,返回0。…

[洛谷P5048][Ynoi2019模擬賽]Yuno loves sqrt technology III

題目大意:有$n(n\leqslant5\times10^5)$個數,$m(m\leqslant5\times10^5)$個詢問,每個詢問問區間$[l,r]$中眾數的出現次數 題解:分塊,設塊大小為$S$,先可以預處理出兩兩塊之間的眾數出現次數,復雜…

C#接口實現多態

我比較喜歡對感興趣的理論進行反復的理解甚至理解背誦下來,接下來再復習一下什么叫多態(哈哈哈) 多態:在同一粒度視圖下對相同類型的事物不做區別的統一處理 接下來看一下接口和引擎類是如何實現多態的: 一、 1、創建了…

docker 網絡 不好用 docker: Error response from daemon: failed to create endpoint jovial_wing on network b

啟動容器時,有可能會遇到如下問題,比如啟動redis容器: sudo docker run -d -p 6379:6379 --name redis redis:latest Linux代碼docker: Error response from daemon: failed to create endpoint redis on network bridge: iptables failed: …

hadoop-hdfs-存儲模型-架構模型-角色介紹

轉載于:https://www.cnblogs.com/LXL616/p/10803978.html

docker 鏡像 導入導出

很喜歡玩docker,但最新遇到一個問題,公司給的新機器的dns有問題,導致pull不下來鏡像。 沒辦法了,沒有鏡像什么神馬都干不了,又不能花很多時間去搭建私有的鏡像庫,只有另尋辦法了。 廢話少說,經…

使用Nginx+uWSGI部署Django項目

1.linux安裝python3環境 參考鏈接:https://www.cnblogs.com/zzqit/p/10087680.html 2.安裝uwsgi pip3 install uwsgiln -s /usr/local/python3/bin/uwsgi /usr/local/bin/uwsgi #建立軟鏈接uwsgi --version #檢查安裝成功 3.基于uwsgidjango項目部署 django項目目…

Nagios使用check_mysql_health插件監控Mysql主機

基本信息 Nagios:Nagios core 4.4.3Nagios Plugins:check_mysql_health 2.2.2Mysql-server: 192.168.0.91db user:db操作流程:下載插件->安裝插件->配置command->添加主機->添加服務安裝插件 下載 wget https://labs.…

lsof使用

簡介 lsof(list open files)是一個列出當前系統打開文件的工具。在linux環境下,任何事物都以文件的形式存在,通過文件不僅僅可以訪問常規數據,還可以訪問網絡連接和硬件。所以如傳輸控制協議 (TCP) 和用戶數據報協議 (UDP) 套接字等&#xf…

解題:2017清華集訓 無限之環

題面 費用流 把每種水管再拆出來四個方向的接頭,然后根據水管的形狀連出旋轉時的代價。最后黑白染色成二分圖,然后白點對應的接頭向黑點對應的接頭連邊,源點向白點自己連邊,黑點自己向匯點連邊。 怎么連邊?我是大力討論…

Node.js學習之(第二章:exports和module.exports)

前言 Node中,每個模塊都有一個exports接口對象,我們需要把公共的方法或者字符串掛載在這個接口對象中,其他的模塊才可以使用。 Node.js中只有模塊作用域,默認兩個模塊之間的變量,方法互不沖突,互不影響&…

docker命令及掛載

常用命令所有鏡像:docker images當前執行:docker ps提交保存docker容器: docker commit進入到對應服務:docker attach <container id>已經執行帶容器:docker ps -l根據名稱啟動通過8081端口察看docker容器里的8080:docker run -i -t -d -p 8081:8080 -p23:22 ubuntu:ubun…

列表,元組,字典類的常見簡單方法

一.列表&#xff08;list類&#xff09; 1.append&#xff08;&#xff09;&#xff1a;追加一個參數&#xff0c;參數可以為字符串&#xff0c;數字或列表等&#xff0c;將參數視為一個整體 2.clear&#xff08;&#xff09;&#xff1a;直接清空列表里的所有 3.count&#xf…

與圖論的邂逅05:最近公共祖先LCA

什么是LCA&#xff1f; 祖先鏈 對于一棵樹T&#xff0c;若它的根節點是r&#xff0c;對于任意一個樹上的節點x&#xff0c;從r走到x的路徑是唯一的(顯然)&#xff0c;那么這條路徑上的點都是并且只有這些點是x的祖先。這些點組成的鏈(或者說路徑)就是x的祖先鏈。 LCA 根據名字來…

MAC地址進行驗證的方法

需要對對應的MAC地址進行驗證的方法&#xff0c;以為很簡單就能過&#xff0c;鼓搗了半天以后才發現&#xff0c;我的機器是window7&#xff0c;查詢出來是亂碼&#xff0c;居然不給支持。沒辦法在網上繼續找資料。終于找到了&#xff0c;貼上來&#xff0c;以備不時之需。 東西…

JAVA 分布式環境 Redis互斥鎖

開始的時候項目沒有添加互斥鎖&#xff0c;用的依然是老的思路&#xff0c;在并發量增加的情況下&#xff0c;遇到了很多的問題&#xff0c;包括數據庫重復讀等&#xff0c;想了下考慮增加 互斥鎖來排序對單個資源的操作。 Target(ElementType.METHOD) Retention(RetentionPoli…

相機添加多張圖片css布局

<section class"feedback-upload"><aside class"photos"><div></div><div class"camera"></div></aside><aside class"tips"><div><span>選填0~4</span></div&…

移動端滑動操作學習

(function(window,document){var Slide function(box,judge,fun){if (!(this instanceof Slide)) return new Slide(box,judge,fun);var startx,starty;box.addEventListener("touchstart", function(e) {e.preventDefault(); // 阻止瀏覽器默認事件startx parseIn…

深入學習Oracle分區表及分區索引

關于分區表和分區索引(About Partitioned Tables and Indexes)對于10gR2而言&#xff0c;基本上可以分成幾類&#xff1a; ?    Range(范圍)分區 ?    Hash(哈希)分區 ?    List(列表)分區 ?    以及組合分區&#xff1a;Range-Hash,R…