|
有的時(shí)候JDBC運(yùn)行的不夠理想,這就促使我們寫一些與特定數(shù)據(jù)庫相關(guān)的存儲(chǔ)過程。作為一個(gè)替換方案,不妨試一下Statement的批處理特征,看看一次執(zhí)行所有的SQL語句是否會(huì)帶來速度的提升。 存儲(chǔ)過程最簡單的形式就是整個(gè)過程只包含一組SQL語句。將這些語句放到一起能容易管理也可以提高運(yùn)行速度。Statement類具有包含一串SQL語句的能力,因此它允許所有的SQL語句在一個(gè)數(shù)據(jù)庫會(huì)話中被執(zhí)行,從而避免了向數(shù)據(jù)庫進(jìn)行一連串的執(zhí)行調(diào)用。 使用批處理功能涉及到兩個(gè)方法: addBatch(String)方法 executeBatch方法 addBatch方法可以接受一段標(biāo)準(zhǔn)的SQL(如果你使用一個(gè)Statement)作為參數(shù),也可以什么參數(shù)都不帶(如果你使用一個(gè)PreparedStatement)。 executeBatch方法接著執(zhí)行SQL語句,返回一個(gè)int型數(shù)組。這個(gè)數(shù)組包括每條語句影響到的行數(shù)。如果在一個(gè)批處理中使用是一個(gè)SELECT或者其它只返回結(jié)果的語句,那么將會(huì)產(chǎn)生一個(gè)SQLException異常。 下面是一個(gè)簡單的java.sql.Statement的例子: Statement stmt = conn.createStatement(); stmt.insert("DELETE FROM Users"); stmt.insert("INSERT INTO Users VALUES(‘rod‘, 37, ‘circle‘)"); stmt.insert("INSERT INTO Users VALUES(‘jane‘, 33, ‘triangle‘)"); stmt.insert("INSERT INTO Users VALUES(‘freddy‘, 29, ‘square‘)"); int[] counts = stmt.executeBatch(); 使用PreparedStatement會(huì)稍有不同。它只能處理一段SQL語句,但可以帶很多參數(shù)。下面的是使用PreparedStatement重寫的上面的例子: //注意我們并沒有做任何刪除動(dòng)作 PreparedStatement stmt = conn.prepareStatement( _ "INSERT INTO Users VALUES(?,?,?)" ); User[ ] users = ...; for(int i=0; i<users.length; i++) { stmt.setInt(1, users[i].getName()); stmt.setInt(2, users[i].getAge()); stmt.setInt(3, users[i].getShape()); stmt.addBatch( ); } int[ ] counts = stmt.executeBatch(); 這是處理那些不知道具體執(zhí)行次數(shù)的SQL代碼的一個(gè)好方法。沒有批處理,如果要添加50個(gè)用戶,其性能可能受到影響。如果誰寫了一段添加10000個(gè)用戶的腳本,其運(yùn)行速度就難以忍受。增加批處理將有助于提升性能,在后一種情況里,甚至可以改善代碼的可讀性。 使用PreparedStatement減少開發(fā)時(shí)間 JDBC(Java Database Connectivity,java數(shù)據(jù)庫連接)的API中的主要的四個(gè)類之一的java.sql.Statement要求開發(fā)者付出大量的時(shí)間和精力。 在使用Statement獲取JDBC訪問時(shí)所具有的一個(gè)共通的問題是輸入適當(dāng)格式的日期和時(shí)間戳:2002-02-05 20:56 或者 02/05/02 8:56 PM。通過使用java.sql.PreparedStatement,這個(gè)問題可以自動(dòng)解決。一個(gè)PreparedStatement是從 java.sql.Connection對(duì)象和所提供的SQL字符串得到的,SQL字符串中包含問號(hào)(?),這些問號(hào)標(biāo)明變量的位置,然后提供變量的值, 最后執(zhí)行語句,例如: Stringsql = "SELECT * FROM People p WHERE p.id = ? AND p.name = ?";使用PreparedStatement的另一個(gè)優(yōu)點(diǎn)是字符串不是動(dòng)態(tài)創(chuàng)建的。下面是一個(gè)動(dòng)態(tài)創(chuàng)建字符串的例子: Stringsql = "SELECT * FROM People p WHERE p.i = "+id;
這允許JVM(JavaVirtual Machine,Java虛擬機(jī))和驅(qū)動(dòng)/數(shù)據(jù)庫緩存語句和字符串并提高性能。 PreparedStatement也提供數(shù)據(jù)庫無關(guān)性。當(dāng)顯示聲明的SQL越少,那么潛在的SQL語句的數(shù)據(jù)庫依賴性就越小。 由于PreparedStatement具備很多優(yōu)點(diǎn),開發(fā)者可能通常都使用它,只有在完全是因?yàn)樾阅茉蚧蛘呤窃谝恍蠸QL語句中沒有變量的時(shí)候才使用通常的Statement。 在任何你想向數(shù)據(jù)庫運(yùn)行一個(gè)SQL語句的時(shí)候, 你都需要一個(gè) Statement 或 PreparedStatement 實(shí)例。 一旦你擁有了一個(gè) Statement 或 PreparedStatement,你就可以 發(fā)出一個(gè)查詢。 這樣將返回一個(gè) ResultSet 實(shí)例, 在其內(nèi)部包含整個(gè)結(jié)果。 Example 31-1 演示了這個(gè)過程。 Example 31-1. 在 JDBC 里處理一個(gè)簡單的查詢 這個(gè)例子將發(fā)出一個(gè)簡單的查詢?nèi)缓笥靡粋€(gè) Statement打印出每行的第一個(gè)字段。 Statement st = db.createStatement(); 這個(gè)例子將使用 PreparedStatement 發(fā)出和前面一樣的查詢,并且在查詢中制作數(shù)值。 int foovalue = 500; 31.3.1. 使用 Statement或 PreparedStatement 接口在使用 Statement或 PreparedStatement接口時(shí)必須考慮下面的問題:
31.3.2. 使用 ResultSet(結(jié)果集)接口使用 ResultSet接口時(shí)必須考慮下面的問題:
|
|
|