statement prepareStatement的一點體會?

1、PrepareStatement 是預編譯的,對於批量處理(Batch)處理可以大大提高效率,也叫JDBC存儲過程

2、使用Statement對象。在對數據庫只執行一次性存取的時候,用Statement對象進行處理,PrepareStatement對象的開銷比Statement大,對於一次性操作並不會帶來額外的好處。

3、statement每次執行sql語句,相關數據庫都要執行sql語句的編譯,prepareStatement是預編譯的,並且支持Batch處理

**如果只執行一次的話,兩者沒有什麼明顯的差異,如果sql執行多次,預編譯過的sql只需要DBMS運行sql語句,而不必先編譯後執行,預編譯的sql只需要更改其中變量的值,便可重新執行SQL語句。

4、執行許多SQL語句的JDBC程序產生大量的Statement和PrepareStatement,通常認爲prepareStatement對象比Statement更有效,特別是如果帶有不同參數的同一SQL語句被多次執行的時候,PrepareStatement對象允許數據庫預編譯SQL語句,這樣在隨後的運行中key節省時間並增加代碼的可讀性。

5、還有一個更好的原因使我們在企業應用程序中更喜歡使用PreparedStatement對象,那就是安全性。傳遞給PreparedStatement對象的參數可以被強制進行類型轉換,使開發人員可以確保在插入或查詢數據時與底層的數據庫格式匹配。

6、當處理公共Web站點上的用戶傳來的數據的時候,安全性的問題就變得極爲重要。傳遞給PreparedStatement的字符串參數會自動被驅動器忽略。最簡單的情況下,這就意味着當你的程序試着將字符串“D’Angelo”插入到VARCHAR2中時,該語句將不會識別第一個“,”,從而導致悲慘的失敗。幾乎很少有必要創建你自己的字符串忽略代碼。

7、prepareStatement預防絕大多數的SQL注入,SQL語句在程序運行前已經進行了預編譯,在程序運行時第一次操作數據庫之前,SQL語句已經被數據庫分析,編譯和優化,對應的執行計劃也會緩存下來並允許數據庫已參數化的形式進行查詢,當運行時動態地把參數傳給PreprareStatement時,即使參數裏有敏感字符如 or ‘1=1’也數據庫會作爲一個參數一個字段的屬性值來處理而不會作爲一個SQL指令

8、JDBC驅動的最佳化是基於使用的是什麼功能. 選擇PreparedStatement還是Statement取決於你要怎麼使用它們. 對於只執行一次的SQL語句選擇Statement是最好的. 相反, 如果SQL語句被多次執行選用PreparedStatement是最好的.

9、prepareStatement=>JDBC驅動會發送一個網絡請求到數據解析和優化這個查詢. 而執行時會產生另一個網絡請求,而對於Statement, 同一個查詢只會產生一次網絡到數據庫的通訊.

10、使用prepareStatement的Batch批處理功能
直接上例子

connection.setAutoCommit(false);//去掉自動提交事務
PreparedStatement ps = conn.prepareStatement(  
   "INSERT into employees values (?, ?, ?)");  

for (n = 0; n < 100; n++) {  

  ps.setString(name[n]);  
  ps.setLong(id[n]);  
  ps.setInt(salary[n]);  
  ps.addBatch();  
}  
ps.executeBatch();  

使用批量插入的好處: , 當在100次INSERT操作中使用addBatch()方法時, 只有兩次網絡往返. 1次往返是預儲statement, 另一次是執行batch命令. 雖然Batch命令會用到更多的數據庫的CPU週期, 但是通過減少網絡往返,性能得到提高. 記住, JDBC的性能最大的增進是減少JDBC驅動與數據庫之間的網絡通訊. 如果沒有使用批處理則網絡往返101次這樣會耗很多時間,自然效率也就一般

**mysql 5.5.28 批量執行的數據最大限度是多少不清楚,但自己試了1w,2w,3w 都沒問題,記得在url 後面添加:rewriteBatchedStatements=true 表示批量插入,如果不添加的話即使使用addbatch() ,executeBatch() 在後臺入庫的地方還是不會一次請求入庫而是多次請求入庫。

11、使用更加高效的getter方法(字段索引)
JDBC提供多種方法從ResultSet中取得數據, 像getInt(), getString(), 和getObject()等等. 而getObject()方法是最泛化了的, 提供了最差的性能。 這是因爲JDBC驅動必須對要取得的值的類型作額外的處理以映射爲特定的對象. 所以就對特定的數據類型使用相應的方法.
要更進一步的改善性能, 應在取得數據時提供字段的索引號, 例如, getString(1), getLong(2), 和getInt(3)等來替代字段名. 如果沒有指定字段索引號, 網絡交通不會受影響, 但會使轉換和查找的成本增加. 例如, 假設你使用getString(“foo”) … JDBC驅動可能會將字段名轉爲大寫(如果需要), 並且在到字段名列表中逐個比較來找到”foo”字段. 如果可以, 直接使用字段##索引##, 將爲你節省大量的處理時間.

例如, 假設你有一個100行15列的ResultSet, 字段名不包含在其中. 你感興趣的是三個字段 EMPLOYEENAME (字串型), EMPLOYEENUMBER (長整型), 和SALARY (整型). 如果你指定getString(“EmployeeName”), getLong(“EmployeeNumber”), 和getInt(“Salary”), 查詢旱每個字段名必須被轉換爲metadata中相對應的大小寫, 然後才進行查找. 如果你使用getString(1), getLong(2), 和getInt(15). 性能就會有顯著改善.

12、獲取自動生成的鍵值
JDBC3.0之前

//插入行  
int rowcount = stmt.executeUpdate (  
   "insert into table1(name) values ('kd')");  
// 現在爲新插入的行取得磁盤位置 - rowid  
ResultSet rs = stmt.executeQuery (  
   "select rowid from table1 where name = 'kd'");  

這種取得隱含列的方式有兩個主要缺點. 第一, 取得隱含列是在一個獨立的查詢中, 它要透過網絡送到服務器後再執行. 第二, 因爲不是主鍵, 查詢條件可能不是表中的唯一性ID. 在後面一個例子中, 可能返回了多個隱含列的值, 程序無法知道哪個是最後插入的行的值.

JDBC3.0之後

// 插入行並返回鍵值  
int rowcount = stmt.executeUpdate ("insert into table1 (name) values ('kd')", Statement.RETURN_GENERATED_KEYS);   
// 得到生成的鍵值
ResultSet rs = stmt.getGeneratedKeys ();  

現在, 程序中包含了一個唯一性ID, 可以用來作爲查詢條件來快速的存取數據行, 甚至於表中沒有主鍵的情況也可以.

**現在, 程序中包含了一個唯一性ID, 可以用來作爲查詢條件來快速的存取數據行, 甚至於表中沒有主鍵的情況也可以

13、選擇合適的數據類型
接受和發送某些數據可能代價昂貴,當你設計一個schema時,應選擇能被最有效地處理的數據類型,例如,整型數就比浮點數活實處理要快一些,浮點數的定義是數據的內部規定的格式,通常是一種壓縮格式,數據必須被解壓和轉換到另外種樣式,這樣他才能被數據的協議處理

14、獲取ResultSet
通常情況下,請不要寫那種依賴於結果集行數(ResultSet.getRow())的代碼, 因爲驅動程序必須獲取所有的數據集以便知道查詢會返回多少行數據.

15、儘量使用prepareStatement,代碼可讀性,運行高效性,防止sql注入等足夠你有理由選擇prepareStatement

16、光標類型有待研究…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章