如何利用JDBC發(fā)送SQL語句?
Statement對象用于將SQL語句發(fā)送到數(shù)據(jù)庫中。實(shí)際上有三種Statement對象,它們都作為在給定連接上執(zhí)行SQL語句的包容器:Statement、PreparedStatement(它從Statement繼承而來)和CallableStatement(它從PreparedStatement繼承而來)。它們都專用于發(fā)送特定類型的SQL語句:Statement對象用于執(zhí)行不帶參數(shù)的簡單SQL語句;PreparedStatement對象用于執(zhí)行帶或不帶IN參數(shù)的預(yù)編譯SQL語句;CallableStatement對象用于執(zhí)行對數(shù)據(jù)庫已存儲(chǔ)過程的調(diào)用。
Statement接口提供了執(zhí)行語句和獲取結(jié)果的基本方法;PreparedStatement接口添加了處理IN參數(shù)的方法;而CallableStatement添加了處理OUT參數(shù)的方法。
1. 創(chuàng)建Statement對象
建立了到特定數(shù)據(jù)庫的連接之后,就可用該連接發(fā)送SQL語句。Statement對象用Connection的方法createStatement創(chuàng)建,如下列代碼段中所示:
Connection con = DriverManager.getConnection(url,"sunny",""); Statement stmt = con.createStatement();
為了執(zhí)行Statement對象,被發(fā)送到數(shù)據(jù)庫的SQL語句將被作為參數(shù)提供給Statement的方法:
ResultSet rs = stmt.executeQuery("SELECT a,b,c FROM Table2");
2. 使用Statement對象執(zhí)行語句
Statement接口提供了三種執(zhí)行SQL語句的方法:executeQuery、executeUpdate和execute。使用哪一個(gè)方法由SQL語句所產(chǎn)生的內(nèi)容決定。
方法executeQuery用于產(chǎn)生單個(gè)結(jié)果集的語句,例如SELECT語句。方法executeUpdate用于執(zhí)行INSERT、UPDATE或DELETE語句以及SQL DDL(數(shù)據(jù)定義語言)語句,例如CREATE TABLE和DROP TABLE。INSERT、UPDATE或DELETE語句的效果是修改表中零行或多行中的一列或多列。executeUpdate的返回值是一個(gè)整數(shù),指示受影響的行數(shù)(即更新計(jì)數(shù))。對于CREATE TABLE或DROP TABLE等不操作行的語句,executeUpdate的返回值總為零。
執(zhí)行語句的所有方法都將關(guān)閉所調(diào)用的Statement對象的當(dāng)前打開結(jié)果集(如果存在)。這意味著在重新執(zhí)行Statement對象之前,需要完成對當(dāng)前ResultSet對象的處理。應(yīng)注意,繼承了Statement接口中所有方法的PreparedStatement接口都有自己的executeQuery、executeUpdate和execute方法。Statement對象本身不包含SQL語句,因而必須給Statement.execute方法提供SQL語句作為參數(shù)。PreparedStatement對象并不需要SQL語句作為參數(shù)提供給這些方法,因?yàn)樗鼈円呀?jīng)包含預(yù)編譯SQL語句。
CallableStatement對象繼承這些方法的PreparedStatement形式。對于這些方法的PreparedStatement或CallableStatement版本,使用查詢參數(shù)將拋出SQLException。
3. 語句完成
當(dāng)連接處于自動(dòng)提交模式時(shí),其中所執(zhí)行的語句在完成時(shí)將自動(dòng)提交或還原。語句在已執(zhí)行且所有結(jié)果返回時(shí),即認(rèn)為已完成。對于返回一個(gè)結(jié)果集的executeQuery方法,在檢索完ResultSet對象的所有行時(shí)該語句完成。對于方法executeUpdate,當(dāng)它執(zhí)行時(shí)語句即完成。但在少數(shù)調(diào)用方法execute的情況中,在檢索所有結(jié)果集或它生成的更新計(jì)數(shù)之后語句才完成。
有些DBMS將已存儲(chǔ)過程中的每條語句視為獨(dú)立的語句;而另外一些則將整個(gè)過程視為一個(gè)復(fù)合語句。在啟用自動(dòng)提交時(shí),這種差別就變得非常重要,因?yàn)樗绊懯裁磿r(shí)候調(diào)用commit方法。在前一種情況中,每條語句單獨(dú)提交;在后一種情況中,所有語句同時(shí)提交。
4. 關(guān)閉Statement對象
Statement對象將由Java垃圾收集程序自動(dòng)關(guān)閉。而作為一種好的編程風(fēng)格,應(yīng)在不需要Statement對象時(shí)顯式地關(guān)閉它們。這將立即釋放DBMS資源,有助于避免潛在的內(nèi)存問題。
5. 使用方法execute
execute方法應(yīng)該僅在語句能返回多個(gè)ResultSet對象、多個(gè)更新計(jì)數(shù)或ResultSet對象與更新計(jì)數(shù)的組合時(shí)使用。當(dāng)執(zhí)行某個(gè)已存儲(chǔ)過程或動(dòng)態(tài)執(zhí)行未知SQL字符串(即應(yīng)用程序程序員在編譯時(shí)未知)時(shí),有可能出現(xiàn)多個(gè)結(jié)果的情況,盡管這種情況很少見。例如,用戶可能執(zhí)行一個(gè)已存儲(chǔ)過程,并且該已存儲(chǔ)過程可執(zhí)行更新,然后執(zhí)行選擇,再進(jìn)行更新,再進(jìn)行選擇,等等。通常使用已存儲(chǔ)過程的人應(yīng)知道它所返回的內(nèi)容。
因?yàn)榉椒╡xecute處理非常規(guī)情況,所以獲取其結(jié)果需要一些特殊處理并不足為怪。例如,假定已知某個(gè)過程返回兩個(gè)結(jié)果集,則在使用方法execute執(zhí)行該過程后,必須調(diào)用方法getResultSet獲得第一個(gè)結(jié)果集,然后調(diào)用適當(dāng)?shù)膅etXXX方法獲取其中的值。要獲得第二個(gè)結(jié)果集,需要先調(diào)用getMoreResults方法,然后再調(diào)用getResultSet方法。如果已知某個(gè)過程返回兩個(gè)更新計(jì)數(shù),則首先調(diào)用方法getUpdateCount,然后調(diào)用getMoreResults,并再次調(diào)用getUpdateCount。
對于不知道返回內(nèi)容,則情況更為復(fù)雜。如果結(jié)果是ResultSet對象,則方法execute返回true;如果結(jié)果是Javaint,則返回false。如果返回int,則意味著結(jié)果是更新計(jì)數(shù)或執(zhí)行的語句是DL命令。在調(diào)用方法execute之后要做的第一件事情是調(diào)用getResultSet或getUpdateCount。調(diào)用方法getResultSet可以獲得兩個(gè)或多個(gè)ResultSet對象中第一個(gè)對象;或調(diào)用方法getUpdateCount可以獲得兩個(gè)或多個(gè)更新計(jì)數(shù)中第一個(gè)更新計(jì)數(shù)的內(nèi)容。
當(dāng)SQL語句的結(jié)果不是結(jié)果集時(shí),則方法getResultSet將返回null。這可能意味著結(jié)果是一個(gè)更新計(jì)數(shù)或沒有其它結(jié)果。在這種情況下,判斷null真正含義的唯一方法是調(diào)用方法getUpdateCount,它將返回一個(gè)整數(shù)。這個(gè)整數(shù)為調(diào)用語句所影響的行數(shù);如果為-1則表示結(jié)果是結(jié)果集或沒有結(jié)果。如果方法getResultSet已返回null(表示結(jié)果不是ResultSet對象),則返回值-1表示沒有其它結(jié)果。也就是說,當(dāng)下列條件為真時(shí)表示沒有結(jié)果(或沒有其它結(jié)果):
?。ǎ╯tmt.getResultSet()==null)&&(stmt.getUpdateCount()==-1))
如果已經(jīng)調(diào)用方法getResultSet并處理了它返回的ResultSet對象,則有必要調(diào)用方法getMoreResults以確定是否有其它結(jié)果集或更新計(jì)數(shù)。如果getMoreResults返回true,則需要再次調(diào)用getResultSet來檢索下一個(gè)結(jié)果集。如上所述,如果getResultSet返回null,則需要調(diào)用getUpdateCount來檢查null是表示結(jié)果為更新計(jì)數(shù)還是表示沒有其它結(jié)果。
當(dāng)getMoreResults返回false時(shí),它表示該SQL語句返回一個(gè)更新計(jì)數(shù)或沒有其它結(jié)果。因此需要調(diào)用方法getUpdateCount來檢查它是哪一種情況。在這種情況下,當(dāng)下列條件為真時(shí)表示沒有其它結(jié)果:
?。ǎ╯tmt.getMoreResults()==false)&&(stmt.getUpdateCount()==-1))
下面的代碼演示了一種方法用來確認(rèn)已訪問調(diào)用方法execute所產(chǎn)生的全部結(jié)果集和更新計(jì)數(shù):
stmt.execute(queryStringWithUnknownResults); while(true){ introwCount=stmt.getUpdateCount(); if(rowCount>0){//它是更新計(jì)數(shù) System.out.println("Rows changed="+count); stmt.getMoreResults(); continue; } if(rowCount==0){//DDL命令或0個(gè)更新 System.out.println("No rows changed or statement was DDL command"); stmt.getMoreResults(); continue; } //執(zhí)行到這里,證明有一個(gè)結(jié)果集 //或沒有其它結(jié)果 ResultSet rs=stmt.getResultSet(); if(rs!=null){ ...//使用元數(shù)據(jù)獲得關(guān)于結(jié)果集列的信息 while(rs.next()){ ...//處理結(jié)果 stmt.getMoreResults(); continue; } break;//沒有其它結(jié)果 |
|