對應PreparedStatement相信你們都很熟悉,那麼爲何要用PreparedStatement呢?也許你會回答PreparedStatement爲預處理語句,能夠提升數據庫執行效率。也許還會回答用PreparedStatement能夠防止SQL注入。那麼再問下,你以爲你對PreparedStatement有足夠的瞭解嗎,你在項目中PreparedStatement用對了嗎? sql
首先來看下Statement及PreparedStatement執行過程,一個sql語句執行過程當中,將經歷這麼幾個步驟: 數據庫
一、傳輸SQL給數據庫 緩存
二、數據庫驗證並解析SQL 服務器
三、計算Access Plan。數據庫會經過檢測index,statistics來給出最優的訪問計劃。 性能
四、根據訪問計劃進行檢索,返回數據。 優化
在上面步驟中,第3步是很是耗時的。所以,爲了提升性能,數據庫會緩存執行語句以及其Access Plan。這被稱爲statement cache。在statement cache中,sql語句自己爲key,access plan爲value。當相同的sql語句被髮送過來時,數據庫會使用緩存中的access plan以節省cpu時間。 spa
下邊看下Statement執行代碼: code
1
2
3
4
5
6
7
8
|
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。
1
2
3
4
5
6
|
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對象存入鏈接緩存。
若是項目未使用數據庫鏈接池怎麼辦呢,這裏只能告訴你,原理你已經很清楚了,本身實現吧。