序言 對應PreparedStatement相信大家都很熟悉,那么為什么要用PreparedStatement呢?也許你會回答PreparedStatement為預處理語句,可以提高數據庫執行效率。也許還會回答用PreparedStatement可以防止SQL注入。那么再問下,你覺得你對PreparedStatement有足夠
對應PreparedStatement相信大家都很熟悉,那么為什么要用PreparedStatement呢?也許你會回答PreparedStatement為預處理語句,可以提高數據庫執行效率。也許還會回答用PreparedStatement可以防止SQL注入。那么再問下,你覺得你對PreparedStatement有足夠的了解嗎,你在項目中PreparedStatement用對了嗎?
首先來看下Statement及PreparedStatement執行過程,一個sql語句執行過程中,將經歷這么幾個步驟:
1、傳輸SQL給數據庫
2、數據庫驗證并解析SQL
3、計算Access Plan。數據庫會通過檢測index,statistics來給出最優的訪問計劃。
4、根據訪問計劃進行檢索,返回數據。
在上面步驟中,第3步是非常耗時的。因此,為了提高性能,數據庫會緩存執行語句以及其Access Plan。這被稱為statement cache。在statement cache中,sql語句本身為key,access plan為value。當相同的sql語句被發送過來時,數據庫會使用緩存中的access plan以節省cpu時間。
下邊看下Statement執行代碼:
Statement statement = connection.createStatement(); String sql1="Select * from test where id=1"; String sql2="Select * from test where id="; statement.execute(sql1); statement.execute(sql1); statement.execute(sql1); statement.execute(sql2+"2"); statement.execute(sql2+"3");
sql1在第一次執行的時候,需要計算執行計劃。但在第2和3次執行的時候,會使用緩存好的執行計劃,因此后面的sql1不會再重新檢驗語法與計算執行計劃,效率會比第一次高。
sql2卻每次都在變化,在cache中,key為整個sql語句,所以每次sql2都無法命中cache,即使它僅僅參數不同,也必須重新檢驗語法與計算執行計劃,效率自然就低下。
強大的數據庫會在cache命中上做優化,但復雜的語句還是避免不了miss。
PreparedStatement的存在是為了避免sql2的劣勢。看下面code。String sql2="Select * from test where id=?"; PreparedStatement pstmt = connection.prepareStatement(sql2); pstmt.setInt(1,2); pstmt.executQuery(); pstmt.setInt(1,3); pstmt.executQuery();
PreparedStatement的生命周期跟Statement一樣,在一個數據庫連接connection范圍內有效,所以說如果一次連接中對于同一個PreparedStatement處理多次(參數不同),那么用PreparedStatement是可以提高效率,但大多情景都是多次連接中處理同一個PreparedStatement,那么就算使用了PreparedStatement也不能提高效率,比較PreparedStatement的生命周期只在Connection中。那么如何正確的使用PreparedStatement呢?
其實不用緊張,告訴大家個好消息,J2EE服務器的連接池管理器已經實現了緩存的使用。J2EE服務器保持著連接池中每一個連接準備過的prepared statement列表。當我們在一個連接上調用preparedStatement時,應用服務器會檢查這個statement是否曾經準備過。如果是,這個PreparedStatement會被返回給應用程序。如果否,調用會被轉給JDBC驅動程序,然后將新生成的statement對象存入連接緩存。
如果項目未使用數據庫連接池怎么辦呢,這里只能告訴你,原理你已經很清楚了,自己實現吧。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com