JDBC和結果集的操作
1.Class.ForName("xxx");載入驅動器類
2.連線到資料庫
Connection con = DriverManager.getConnection(url, user, password);
3.建立statement物件
PreparedStatement statement = con.prepareStatement(sql);
Statement sta = con.createStatement();
4.執行sql
ResultSet set = statement.executeQuery(); sta.execute(sql);sta.getResultSet();
executeUpdate方法既可以執行諸如INSERT、 UPDATE和DELETE之類的操作,也可以執行諸如CREATE TABLE和DROP TABLE之類的資料定義語句。但是,執行SELECT查詢時必須使用executeQuery方法。另外還有一個execute方法可以執行任意的SQL語句,此方法通常只用於使用者提供的互動式查詢。
5.解析ResultSet得到資料
while(sta.next()){
sta.getString(1);
sta.getString("name");
}
ResultSet類的迭代方法與java.util.Iterator介面稍有不同。對於ResultSet類,迭代器初始化時被設定在第一行之前的位置,必須呼叫next方法將它移動到第一行。另外,它沒有hasNext方法,我們需要不斷地呼叫next,直至該方法返回false。不同的資料型別有不同的訪問器,比如getString和getdouble。每個訪問器都有兩種形式,一種接受數字引數,另一種接受字串引數。當使用數字引數時,我們指的是該數字所對應的列。例如, rs.getString(1)返回的是當前行中第一列的值。與陣列的索引不同,資料庫的列序號是從1開始計算的。
當使用字串引數時,指的是結果集中以該字串為列名的列。例如, rs.getDouble("Price")返回列名為Price的列所對應的值。使用數字引數效率更高一些,但是使用字串參數可以使程式碼易於閱讀和維護。當get方法的型別和列的資料型別不一致時,每個get方法都會進行合理的型別轉換。例如,呼叫rs.getString("Price")時,該方法會將Price列的浮點值轉換成字串。
Statement
ResultSet executeQuery(String sqlQuery)
執行給定字串中的SQL語句,並返回一個用於檢視查詢結果的ResultSet物件。
int executeUpdate(String sqlStatement)
執行字串中指定的INSERT、 UPDATE或DELETE等SQL語句。還可以執行資料定義語言( Data Definition Language, DDL)的語句,如CREATE TABLE。返回受影響的記錄總數,
如果是沒有更新計數的語句,則返回-1。
boolean execute(String sqlStatement)
執行字串中指定的SQL語句。可能會產生多個結果集和更新數。如果第一個執行結果是結果集,則返回true;反之,返回false。呼叫getResultSet或getUpdateCount方法
可以得到第一個執行結果。請參見第4.5.4節中關於處理多結果集的詳細資訊。
ResultSet getResultSet()
返回前一條查詢語句的結果集。如果前一條語句未產生結果集,則返回null值。對於每一條執行過的語句,該方法只能被呼叫一次。
int getUpdateCount()
返回受前一條更新語句影響的行數。如果前一條語句未更新資料庫,則返回-1。對於每一條執行過的語句,該方法只能被呼叫一次。
void close()關閉Statement物件以及它所對應的結果集。
boolean isClosed() 如果語句被關閉,則返回true。
ResultSet
boolean next()
將結果集中的當前行向前移動一行。如果已經到達最後一行的後面,則返回false。注意,初始情況下必須呼叫該方法才能轉到第一行。
Xxx getXxx(int columnNumber)
Xxx getXxx(String columnName)( Xxx指資料型別,例如int、 double、 String、 Date等。)
用給定的列序號或列標籤返回該列的值,並將值轉換成指定型別。列標籤是SQL的AS字句中指定的標籤,在沒有使用AS時,它就是列名。
int findColumn(String columnName)根據給定的列名,返回該列的序號。
void close()立即關閉當前的結果集。
boolean isClosed() 如果語句被關閉,則返回true。
每個Connection物件都可以建立一個或一個以上的Statement物件。同一個Statement對象可以用於多個不相關的命令和查詢。但是,一個Statement物件最多隻能開啟一個結果集。如果需要執行多個查詢操作,且需要同時分析查詢結果,那麼必須建立多個Statement物件。這看上去似乎很有侷限性。但實際上,我們通常並不需要同時處理多個結果集。如果結果集相互關聯,我們就可以使用組合查詢,這樣就只需要分析一個結果。對資料庫進行組合查詢比使用Java程式遍歷多個結果集要高效得多。
當使用完ResultSet、 Statement或Connection物件時,應立即呼叫close方法。這些物件都使用了規模較大的資料結構,所以我們不應該等待垃圾回收器來處理它們。
如果Statement物件上有一個開啟的結果集,那麼呼叫close方法將自動關閉該結果集。同樣地,呼叫Connection類的close方法將關閉該連線上的所有語句。
預備語句preparedStatement
沒有必要在每次開始一個這樣的查詢時都建立新的查詢語句,而是準備一個帶有宿主變數的查詢語句,每次查詢時只需為該變數填入不同的字串就可以反覆多次地使用該語句。這一技術改進了查詢效能,每當資料庫執行一個查詢時,它總是首先通過計算來確定查詢策略,以便高效地執行查詢操作。通過事先準備好查詢並多次重用它,我們就可以確保查詢所需的準備步驟只被執行一次。
在預備查詢語句中,每個宿主變數都用“ ?”來表示。如果存在一個以上的變數,那麼在設定變數值時必須注意“ ?”的位置。必須使用set方法將變數繫結到實際的值上。和ResultSet方法中的get方法類似,針對不同的資料型別也有不同的set方法。
statement.setInt(1, 7);
位置1表示第一個“ ?”。第二個引數指的是賦予宿主變數的值。如果想要重用已經執行過的預備查詢語句,那麼除非使用set方法或呼叫clearParameters方法,否則所有宿主變數的繫結都不會改變。
讀取COB資料
除了數字、字串和日期之外,許多資料庫都可以儲存大物件,例如圖片或其他資料。在SQL中,二進位制大物件稱為BLOB,字元型大物件稱為CLOB。要讀取LOB,需要執行SELECT語句,然後在ResultSet上呼叫getBlob和getClob方法,這樣就可以獲得Blob和Clob型別的物件。要從Blob中獲取二進位制資料,可以呼叫getBytes或getInputStream。如果獲取了Clob物件,那麼就可以通過呼叫getSubString或getCharacterStream來獲取其中的字元資料。要將LOB置於資料庫中,需要在Connection物件上呼叫createBlob或createClob,然後獲取一個用於該LOB的輸出流或寫出器,並將該物件儲存到資料庫中。
Blob
long length()獲取該BLOB的長度。
byte[] getBytes(long startPosition, long length)獲取該BLOB中給定範圍的資料。
InputStream getBinaryStream()
InputStream getBinaryStream(long startPosition, long length)
返回一個輸入流,用於讀取該BLOB中全部或給定範圍的資料。
OutputStream setBinaryStream(long startPosition) 返回一個輸出流,用於從給定位置開始寫入該BLOB。
Clob
long length()獲取該CLOB中的字元總數。
String getSubString(long startPosition, long length)
獲取該CLOB中給定範圍的字元。
Reader getCharacterStream()
Reader getCharacterStream(long startPosition, long length)
返回一個讀入器(而不是流),用於讀取CLOB中全部或給定範圍的資料。
Writer setCharacterStream(long startPosition)
返回一個寫出器(而不是流),用於從給定位置開始寫入該CLOB。
多結果集
在執行儲存過程,或者在使用允許在單個查詢中提交多個SELECT語句的資料庫時,一個查詢有可能會返回多個結果集。下面是獲取所有結果集的步驟:
1. 使用execute方法來執行SQL語句。
2. 獲取第一個結果集或更新計數。
3. 重複呼叫getMoreResults方法以移動到下一個結果集(這個呼叫會自動關閉前一個結
果集)。
4. 當不存在更多的結果集或更新計數時,完成操作。
可滾動和更新的結果集
預設情況下,結果集是不可滾動和不可更新的。為了從查詢中獲取可滾動的結果集,必須使用以下方法得到一個不同的Statement物件
Statement sta = connect.createStatement(type,concurrenry)
PreparedStatement s = connect.preparedStament(xxx,type,concurrenry)
type
TYPE_FORWARD_ONLY 結果集不能滾動
TYPE_SCROLL_INSENSITIVE 結果集可以滾動,但對資料庫變化不敏感
TYPE_SCROLL_SENSITIVE 結果集可以滾動,且對資料庫變化敏感
concurrenry
CONCUR_READ_ONLY 結果集不能用於更新資料庫(預設值)
CONCUR_UPDATABLE 結果集可以用於更新資料庫
生成了結果集之後就可以使用一些方法了set.next(),set.previous(),set.relative(n),set.absolute(n),first、
last、 beforeFirst和afterLast這些簡便方法用於將游標移動到第一行、最後一行、第一行之前或最後一行之後。最後, isFirst、 isLast、 isBeforeFirst和isAfterLast用於測試游標是否位於這些特殊位置上.
並非所有的查詢都會返回可更新的結果集。如果查詢涉及多個表格的連線操作,那麼它所產生的結果集將是不可更新的。如果查詢只涉及一個表格,或者在查詢時是使用主鍵連線多個表格的,那麼它所產生的結果集將是可更新的結果集。可以呼叫ResultSet類中的getConcurrency方法來確定結果集是否是可更新的。
所有對應於SQL型別的資料型別都配有updateXxx方法,比如updateDouble,updateString等。與getXxx方法相同,在使用updateXxx方法時必須指定列的名稱或序號。然後,你可以給該欄位設定新的值。updateXxx方法改變的只是結果集中的行值,而非資料庫中的值。當更新完行中的欄位值後,必須呼叫updateRow方法,這個方法將當前行中的所有更新資訊傳送給資料庫。呼叫updateRow方法就將游標移動到其他行上,那麼所有的更新資訊都將被行集丟棄,而且永遠也不會被傳遞給資料庫。還可以呼叫cancelRowUpdates方法來取消對當前行的更新。
如果想在資料庫中新增一條新的記錄,首先需要使用moveToInsertRow方法將游標移動到特定的位置,我們稱之為插入行( insert row)。然後,呼叫updateXxx方法在插入行的位置上建立一個新的行。在上述操作全部完成之後,還需要呼叫insertRow方法將新建的行傳送給資料庫。完成插入操作後,再呼叫moveToCurrentRow方法將游標移回到呼叫moveToInsertRow方法之前的位置。
ResultSet類中的updateRow、 insertRow和deleteRow方法的執行效果等同於SQL命令中的UPDATE、 INSERT和DELETE。不過,習慣於Java程式語言的程式設計師通常會覺得使用結果集來操控資料庫要比使用SQL語句自然得多。
行集
可滾動的結果集雖然功能強大,卻有一個重要的缺陷:在與使用者的整個互動過程中,必須始終與資料庫保持連線。使用者也許會離開電腦旁很長一段時間,而在此期間卻始終佔有著資料庫連線。這種方式存在很大的問題,因為資料庫連線屬於稀有資源。在這種情況下,我們可以使用行集。 RowSet介面繼承了ResultSet介面,卻無需始終保持與資料庫的連線。
如下所示為javax.sql.rowset包提供的介面,它們都擴充套件了RowSet介面:
CachedRowSet允許在斷開連線的狀態下執行相關操作。
WebRowSet物件代表了一個被快取的行集,該行集可以儲存為XML檔案。該檔案可以移動到Web應用的其他層中,只要在該層中使用WebRowSet重新開啟該檔案即可。
FilteredRowSet和JoinRowSet介面支援對行集的輕量級操作,它們等同於SQL中的SELECT和JOIN操作。上述兩個介面的操作物件是儲存在行集中的資料,因此執行時無需建立資料庫連線。
JdbcRowSet是ResultSet介面的一個瘦包裝器。它從RowSet中繼承了get方法和set方法,從而將一個結果集轉換成一個bean。
一個被快取的行集包含了一個結果集中所有的資料。 CachedRowSet是ResultSet介面的子介面,所以你完全可以像使用結果集一樣來使用被快取的行集。被快取的行集有一個非常重要的優點:斷開資料庫連線後仍然可以使用行集。
甚至可以修改被快取的行集中的資料。當然,這些修改不會立即反饋到資料庫中。相反,必須發起一個顯式的請求,以便讓資料庫真正接受所有修改。此時CachedRowSet類會重新連線到資料庫,並通過執行SQL命令向資料庫中寫入所有修改後的資料。
在填充了行集之後,資料庫中的資料發生了改變,這顯然容易造成資料不一致性。為了解決這個問題,參考實現會首先檢查行集中的原始值(即修改前的值)是否與資料庫中的當前值一致。如果一致,那麼修改後的值將覆蓋資料庫中的當前值。否則,將丟擲SyncProviderException異常,且不向資料庫寫回任何值。
RowSet
String getURL()
void setURL(String url)獲取或設定資料庫的URL。
String getUsername()
void setUsername(String username)獲取或設定連線資料庫所需的使用者名稱。
String getPassword()
void setPassword(String password)獲取或設定連線資料庫所需的密碼。
String getCommand()
void setCommand(String command)獲取或設定向行集中填充資料時需要執行的命令。
void execute()
通過執行使用setCommand方法設定的命令集來填充行集。為了使驅動管理器可以獲得連線,必須事先設定URL、使用者名稱和密碼。
CachedRowSet
void execute(Connection conn)
通過執行使用setCommand方法設定的命令集來填充行集。該方法使用給定的連線,並負責關閉它。
void populate(ResultSet result)將指定的結果集中的資料填充到被快取的行集中。
String getTableName()
void setTableName(String tableName)
獲取或設定資料庫表名稱,填充被快取的行集時所需的資料來自於該表。
int getPageSize()
void setPageSize(int size)獲取和設定頁的尺寸。
boolean nextPage()
boolean previousPage()
載入下一頁或上一頁,如果要載入的頁存在,則返回ture。
void acceptChanges()
void acceptChanges(Connection conn)
重新連線資料庫,並寫回行集中修改過的資料。如果因為資料庫中的資料已經被修改而導致無法寫回行集中的資料,該方法可能會丟擲SyncProviderException異常。