java.sql.preparedstatement和java.sql.statement的區別

來源:互聯網
上載者:User

標籤:

本文轉自CSDN,然後整理了一遍。原文出處:CSDN

JDBC(java database connectivity,java資料庫連接)的api中的主要的四個類之一的java.sql.statement要求開發人員付出大量的時間和精力。在使用statement擷取JDBC訪問時所具有的一個共通的問題是輸入適當格式的日期和時間戳記:2002-02-0520:56 或者 02/05/02 8:56 pm。

通過使用java.sql.preparedstatement,這個問題可以自動解決。一個preparedstatement是從java.sql.connection對象和所提供的sql字串得到的,sql字串中包含問號(?),這些問號標明變數的位置,然後提供變數的值,最後執行語句,例如:

1 String sql = "select * from people p where p.id = ? and p.name =?";2 PreparedStatement ps = conn.prepareStatement(sql);3 ps.setint(1,id);4 ps.setstring(2,name);5 ResultSet rs = ps.executequery();
PreparedStatement

使用preparedstatement的另一個優點是字串不是動態建立的。下面是一個動態建立字串的例子:

String sql = "select * from people p where p.i = "+id;


這允許jvm(javavirtualmachine,java虛擬機器)和驅動/資料庫緩衝語句和字串並提高效能。preparedstatement也提供資料庫無關性。當顯示聲明的sql越少,那麼潛在的sql語句的資料庫依賴性就越小。由於preparedstatement具備很多優點,開發人員可能通常都使用它,只有在完全是因為效能原因或者是在一行sql語句中沒有變數的時候才使用通常的statement。一個完整的preparedstatement的例子:

 1 package jstarproject; 2 import java.sql.*; 3  4 public class mypreparedstatement { 5  6 private final stringdb_driver="com.microsoft.JDBC.sqlserver.sqlserverdriver"; 7 private final string url ="JDBC:microsoft:sqlserver://127.0.0.1:1433;databasename=pubs"; 8  9 public mypreparedstatement()10 {11 }12 public void query() throws sqlexception{13 connection conn = this.getconnection();14 string strsql = "select emp_id from employee where emp_id =?";15 preparedstatement pstmt = conn.preparestatement(strsql);16 pstmt.setstring(1,"pma42628m");17 resultset rs = pstmt.executequery();18 19 while(rs.next()){20 string fname = rs.getstring("emp_id");21 system.out.println("the fname is " + fname);22 }23 rs.close();24 pstmt.close();25 conn.close();26 27 }28 private connection getconnection() throws sqlexception{29 // class.30 connection conn = null;31 try {32 class.forname(db_driver);33 conn = drivermanager.getconnection(url,"sa","sa");34 }35 catch (classnotfoundexception ex) {}36 return conn;37 }38 //main39 public static void main(string[] args) throws sqlexception {40 mypreparedstatement JDBCtest1 = new mypreparedstatement();41 JDBCtest1.query();42 }43 }
例子

為什麼要始終使用PreparedStatement代替Statement?為什麼要始終使用PreparedStatement代替Statement?


在JDBC應用中,如果你已經是稍有水平開發人員,你就應該始終以PreparedStatement代替Statement.也就是說,在任何時候都不要使用Statement.
基於以下的原因:
一.代碼的可讀性和可維護性.
雖然用PreparedStatement來代替Statement會使代碼多出幾行,但這樣的代碼無論從可讀性還是可維護性上來說.都比直接用Statement的代碼高很多檔次:

stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4)values(‘"+var1+"‘,‘"+var2+"‘,"+var3+",‘"+var4+"‘)");

perstmt = con.prepareStatement("insert into tb_name(col1,col2,col2,col4)values (?,?,?,?)");
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();

不用我多說,對於第一種方法.別說其他人去讀你的代碼,就是你自己過一段時間再去讀,都會覺得傷心.

為什麼PreparedStatement 很重要, 以及怎樣"正確"使用他們.

資料庫有一個艱苦的工作. 它們不斷地從許多用戶端讀取 SQL 查詢, 對資料進行儘可能高效的 查詢. 處理語句可能成為一個代價較高的操作, 但是現在資料庫都是很好的設計, 這樣這個困難 被減到最小. 但是這些最佳化需要應用程式開發人員的協助,這篇文章給你展示一下怎樣正確使用 PreparedStatement 來漂亮地協助資料庫執行這些最佳化.

一個資料庫怎樣執行一條語句?

顯然, 不要希望這裡有許多細節; 我們只看一下對這篇文章比較重要的部分. 當一個資料庫接收 到一條語句的時候, 資料庫引擎首先解析這條語句, 查看語法錯誤. 一旦語句解析了, 資料庫 需要找出最有效方法來執行這條語句. 這個計算起來代價很大. 資料庫檢查什麼索引(如果有 的話)能有所協助, 或者它是否能全部讀出一張表中所有的記錄. 資料庫根據這些關於資料庫所 存資料的統計數字來找出最好的辦法. 一旦制訂出查詢方案, 就可以由資料庫引擎來執行.

需要 CPU 來產生訪問方案. 理想的情況, 如果我們把相同的語句給資料庫發送兩次, 我們期望 資料庫重用第一條記錄的訪問方案. 這會比第二次重新產生方案要使用較少的 CPU.

語句緩衝

資料庫可以進行調節來做語句緩衝. 通常包含一些類型的語句緩衝. 緩衝使用語句本身作為關鍵 字, 訪問方案和相應的語句儲存在緩衝區中. 這樣就允許資料庫引擎對以前執行過的語句所使用 的訪問方案進行重用. 舉個例子來說, 如果我們向資料庫發送這樣一條語句 "select a, b from t where c = 2", 計算好的訪問方案就放入緩衝區了. 如果我們以後再使用同樣的語 句, 資料庫就能重用以前的訪問方案, 這樣就能節省 CPU.

但是要注意, 整條語句是一個關鍵字. 例如, 如果我們後來發送的語句是 "selecta,bfrom t where c = 3", 那麼就不會找出以前的訪問方案. 因為 "c=3" 和 "c=2"是不一樣的. 所以, 例如:

     For(int I = 0; I < 1000; ++I)
{
PreparedStatement ps = conn.prepareStatement("select a,b from t where c = " + I);
ResultSet rs = Ps.executeQuery();
Rs.close();
Ps.close();
}

這裡不會用到緩衝. 每次迴圈向資料庫發送一條不同的 SQL 陳述式. 每次迴圈都重新計算新的訪問 方案, 用這種方法我們會浪費大量的 CPU 週期. 但是, 看看下一個片段:

PreparedStatement ps = conn.prepareStatement("select a,b from twhere c= ?");
For(int I = 0; I < 1000; ++I)
{
ps.setInt(1, I);
ResultSet rs = ps.executeQuery();
Rs.close();
}
ps.close();

這樣就會高效得多. 發送給資料庫的語句在 sql 中使用 @#[email protected]# 符號來參數化. 這意味著每次迴圈 發送的是同一條語句, 在 "c=?" 部分帶有不同的參數. 這樣就允許資料庫重用語句的訪問方案, 是程式在資料庫內部運行得更高效. 這基本上能使你的程式運行得更快, 或者使資料庫使用者能更多 地使用 CPU.

PreparedStatement 和 J2EE 伺服器

當我們使用 J2EE 伺服器的時候, 事情會變得更加複雜. 通常情況下, 一個預先準備好的語句 (prepared statement) 是和一個單獨的資料庫連接相關聯的. 當串連關閉時,語句就被丟棄 了. 一般來說, 一個胖用戶端應用程式在得到一個資料庫連接後會一直保持到程式結束. 它會使用 兩種方法建立所有的語句: 急切建立(eagerly) 或者 懶惰建立(lazily). Eagerly是說, 當程式啟動時全部建立. Lazily是說隨用隨建立. 急切的方法會在程式啟動時有些延時, 但是一旦程式啟動以後, 運行很好. 懶惰的方法啟動很快, 但是當程式運行時, 預先準備的語句在第一次使用是建立. 這就會造成效能不平衡, 知道所有的 語句都準備好了, 但是最終程式會和急切方法一樣快. 哪一種最好要看你需要的是快速啟動還是 均衡的效能.

一個 J2EE 應用程式所帶來的問題就是它不能像這樣工作. 它只在一個請求的存留時間中保持一個 串連. 這意味著在他處理每一個請求時都會重新建立語句, 就不象胖用戶端只建立一次, 而不是每 個請求都建立那樣有效,當 J2EE 伺服器給你的程式一個串連時, 並不是一個真正的串連, 而是一個經過封裝的. 你可以 通過查看那個串連的類的名字來檢驗一下. 它不是一個資料庫的 JDBC串連, 是你的伺服器建立 的一個類. 通常, 如果你調用一個串連的 close 方法, 那麼JDBC 驅動程式會關閉這個串連. 我們希望的是當 J2EE 應用程式調用 close 的時候,串連會返回到串連池中. 我們通過設計一個 代理的 JDBC 串連類來做這些, 但看起來就象是實際的串連. 當我們調用這個串連的任何方法時, 代理類就會把請求前遞給實際的串連. 但是, 當我們調用類似 close 的方法時, 並不調用實際 串連的 close 方法, 只是簡單地把串連返回給串連池, 然後把代理串連標記為無效, 這樣當它 被應用程式重新使用時, 我們會得到異常.

封裝是非常有用的, 因為它協助 J2EE 應用程式伺服器實現者比較聰明地加上預先準備語句的 支援. 當程式調用 Connection.prepareStatement 時, 由驅動程式返回一個 PreparedStatement 對象. 當應用程式得到它時, 儲存這個控制代碼, 並且在請求完成時, 關閉 請求之前關閉這個控制代碼. 但是, 在串連返回到串連池之後, 以後被同樣或者
另一個應用程式重用時, 那麼, 我們就理論上希望同樣的 PreparedStatement 返回給應用程式.

J2EE PreparedStatement 緩衝

J2EE PreparedStatement 緩衝由 J2EE 伺服器內部的串連池管理器使用一個緩衝區來 實現. J2EE 伺服器在串連池中儲存一個所有資料庫的預先準備語句的一個列表.當一個程式 調用一個串連的prepareStatement 方法時, 伺服器先檢查這個語句是否已經有了, 如果 是, 相應的 PreparedStatement 就在緩衝區內, 就返回給應用程式, 如果不是, 請求就 會傳遞給 JDBC 驅動程式, 請求/預先準備語句 對象就會加入到緩衝區裡.

對於每一個串連我們需要一個緩衝區, 因為這是 JDBC 驅動程式的工作要求. 任何返回的 preparedStatement 都是針對這個串連的.

如果我們要利用緩衝區的優勢, 要使用和前面相同的規則. 我們需要使用參數話的查詢, 這樣 它們就會和已經在緩衝區的某一個匹配. 大多數應用程式伺服器都允許你調整緩衝區的大小.

概要

總之, 對於預先準備語句, 我們應該使用參數化的查詢. 這樣允許資料庫重用已經存在的訪問 方案, 從而減輕資料庫的負擔. 這樣的緩衝區是這個資料庫範圍的, 所以你可以安排你所有的 應用程式, 使用相似的參數化的 SQL, 就會提高這樣的緩衝區方案的效率, 因為一個應用程式 可以使用另一個應用程式的語句. 一個應用伺服器的優勢也在於此, 因為訪問資料庫的邏輯應該 集中在資料訪問層上(OR 映射, 實體bean 或者直接 JDBC).

最後, 預先準備語句的正確使用也讓你利用應用程式伺服器的預先準備語句的緩衝區的好處. 會提高你的應用程式的效能, 因為應用程式通過對以前的預先準備語句的重用減少 JDBC 驅動程式調用的次數. 這樣使它能和胖用戶端的效率競爭, 並且去掉了不能保持一個長期 串連的壞處.

如果你使用參數化的預先準備語句, 就可以提高資料庫和你的伺服器端的代碼的效率. 這些提高 都會允許你的應用程式提高效能.

 

java.sql.preparedstatement和java.sql.statement的區別

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.