MYSQL4.1及更高版本支持服務器端準備語句(Prepared Statements), 它使用增強的二進制客戶端/服務器協議在客戶端和服務器之間高效的發送數據,可以通過支持這種行協議的編程庫來訪問準備語句,列入MYSQL CAPI,MYSQL Connector/J和MYSQL Connector/NET 爲JAVA和.NET提供了同樣的訪問接口。它也有SQL語言的訪問接口。
創建準備語句時,客戶端庫會像服務器發送一個實際查詢的原型,然後服務器對該原型進行解析和處理,將部分優化過的原型保存起來,並且給客戶端返回一個狀態句柄(State Handle) 客戶端可以通過定義狀態句柄重複的執行查詢。
可以按下面的方式準備查詢:
INSERT INTO table(col1,col2,col3) VALUES(?,?,?);
MYSQL爲準備語句提供了SQL語言接口。例如:
SET @sql = 'SELECT col1,col2,col3' FROM table where col1 = ?';
PREPARE stmt_fetch_actor FROM @sql;
SET @name = 'test';
EXECUTE smtm_fetch_actor USING @name;
DEALLOCATE PREPARE smtm_fetch_actor;
在MYSQL 5.0中可以在存儲過程中使用準備語句。
準備語句會比多次執行查詢效率高很多,具體原因如下:
1.服務器只需要解析一次查詢,這節約瞭解析和其他開銷
2.因爲服務器緩存了一部分執行計劃,所以它只需要執行某些優化步驟一次。
通過二進制發送參數比通過ASCII碼要快的多,比如,通過二進制發送DATE類型的參數只需要3字節,但通過ASCII碼發送需要10個字節。解決的效果對於BLOB和TEXT類型最爲顯著。因爲他們可以成塊的發送。而不是一個個的發送。二進制協議也幫客戶端節約了內存,同時減少了網絡開銷和數據從本身的類型轉換爲非二進制協議的開銷。
3.整個查詢不會被髮送到服務器。只有參數纔會被髮送,減少了網絡流量。
4.MYSQL直接吧參數保存在服務器的緩衝區內,不需要在內存中到處拷貝數據。
5.準備語句對於安全性也有好處,它不需要在應用程序中對值進行轉移和加引號。這更加方便,並且減少了SQL遭受注入攻擊和其他攻擊的可能(永遠也不能信任用戶的輸入,即使使用準備語句也不能)
只有準備語句能使用二進制協議,使用普通的MSYQL_QUERY()函數提交查詢不會使用二進制協議,
準備語句的侷限:
1.準備語句只針對一個連接,所以另外的連接不能使用同樣的句柄,處於同樣的原因,一個先斷開再重新連接的客戶端會丟失句柄(連接池活持續連接會減輕這個問題)
2.準備語句不能使用MYSQL5.0以前的版本緩存
3.使用準備語句並不總是高效,如果只使用一次準備語句,那麼準備它花費的時間可能比執行一次平常的SQL語句更長,準備語句也需要在服務器和客戶端之間進行額外的信息交互。
4.現在不能在存儲函數內部使用準備語句,但是可以在存儲過程中使用準備語句。
5.如果忘記銷燬準備語句,那麼就有可能引起資源泄露,這會小號相當多的服務器資源,同樣,因爲對存儲語句的數量有一個全局性的限制,所以一個錯誤可能會干擾其他使用準備語句的連接。