2006 年 4 月 10 日
Java 5 在 Java Database Connectivity (JDBC) 方面加強了支持,其中加入了新的包 javax.sql.rowset,javax.sql.rowset.serial,javax.sql.rowset.spi。本文將通過(guò)實(shí)例來(lái)演示這些新的特性。
RowSet 新特性簡(jiǎn)介
Java 5在Java Database Connectivity (JDBC)方面加強了支持,其中加入了新的包javax.sql.rowset,javax.sql.rowset.serial,javax.sql.rowset.spi。從RowSet接口繼承規定了五個(gè)新的接口:
1. CachedRowSet: CachedRowset可以不用與數據源建立長(cháng)期的連接,只有當從數據庫讀取數據或是往數據庫寫(xiě)入數據的時(shí)候才會(huì )與數據庫建立連接,它提供了一種輕量級的訪(fǎng)問(wèn)數據庫的方式,其數據均存在內存中。
2. JdbcRowSet:對ResultSet的對象進(jìn)行包裝,使得可以將ResultSet對象做為一個(gè)JavaBeans ™ 組件。
3. FilteredRowSet:繼承自CachedRowSet,可以根據設置條件得到數據的子集。
4. JoinRowSet:繼承自CachedRowSet,可以將多個(gè)RowSet對象進(jìn)行SQL Join語(yǔ)句的合并。
5. WebRowSet:繼承自CachedRowSet,可以將WebRowSet對象輸出成XML格式。
下面分別演示如何使用這五個(gè)新接口。
實(shí)驗環(huán)境
IBM DB2 Universal 8.1
數據庫名:DemoDB
數據庫用戶(hù)名:db2admin
數據庫密碼:password
CachedRowSet
CachedRowSet可以通過(guò)調用populate(ResuletSet rs)來(lái)生成數據,一旦獲得數據,CachedRowSet就可以斷開(kāi)與數據庫的連接,直到往數據庫寫(xiě)入數據的時(shí)候才需建立連接。
可以使用自己擴展的或是使用Reference Implement的實(shí)現類(lèi)進(jìn)行訪(fǎng)問(wèn)數據庫。下面的代碼演示了如何根據ResultSet建立一個(gè)CachedRowSet對象,在中斷與數據庫連接的情況下,讀取數據,并做更新,最后再獲取數據庫連接,將更新落實(shí)到數據庫中。
public static void testCachedRowSet(){ Connection conn = null; try { // 獲得數據庫連接 conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD); Statement stmt = conn.createStatement(); // 查詢(xún)數據庫,獲得表數據 ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$ // 根據ResultSet對象生成CachedRowSet類(lèi)型的對象 CachedRowSetImpl crs = new CachedRowSetImpl(); crs.populate(rs); // 關(guān)閉ResultSet rs.close(); // 關(guān)閉數據庫的連接 conn.close(); // 在中斷與數據庫連接的情況下,對CachedRowSet進(jìn)行操作 operateOnRowSet(crs); // 重新獲取與數據庫的連接 conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD); // 將CachedRowSet的內容更新到數據庫 crs.acceptChanges(conn); // 關(guān)閉CachedRowSet crs.close(); // 關(guān)閉數據庫連接 conn.close(); } catch (InstantiationException e) { System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$ } catch (IllegalAccessException e) { System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$ } catch (ClassNotFoundException e) { System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$ }catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } |
其中operateOnRowSet方法遍歷讀取RowSet中的元素,并將id值加1。RowSet允許注冊監聽(tīng)器,可以在光標移動(dòng),RowSet發(fā)生改變時(shí)觸發(fā)。其具體代碼如下:
public static void operateOnRowSet(RowSet rs){ // 為RowSet注冊監聽(tīng)器 MyRowsetListener myListener = new MyRowsetListener(); rs.addRowSetListener(myListener); // 操作RowSet數據 try{ // 遍歷讀取數據 while (rs.next()) { String id = rs.getString("ID");//$NON-NLS-1$ String name = rs.getString("NAME");//$NON-NLS-1$ System.out.println("ID="+id+",NAME="+name);//$NON-NLS-1$ //在id最末位連接"1" rs.updateString(1, id+"1"); } }catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } class MyRowsetListener implements RowSetListener{ // 光標發(fā)生移動(dòng) public void cursorMoved(RowSetEvent event) { System.out.println("cursor moved"); } // row發(fā)生改變 public void rowChanged(RowSetEvent event) { System.out.println("row changed"); } // RowSet發(fā)生改變 public void rowSetChanged(RowSetEvent event) { System.out.println("row set changed"); } } public static void main(String[] args) { try { Class.forName(DB2DRIVER).newInstance(); } catch (InstantiationException e) { System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$ } catch (IllegalAccessException e) { System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$ } catch (ClassNotFoundException e) { System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$ } testCachedRowSet(); } |
上面的程序的運行結果如下:
cursor moved ID=001,NAME=zhou cursor moved ID=002,NAME=zhang cursor moved cursor moved cursor moved cursor moved cursor moved cursor moved row set changed |
并且數據庫中的id更新為0011,0021。
JdbcRowSet
JdbcRowSet功能與ResultSet類(lèi)似,與CachedRowSet不同,JdbcRowSet在操作時(shí)保持與數據庫的連接??梢詫⑴c數據庫連接的URL,用戶(hù)名,密碼以及執行的SQL語(yǔ)句通過(guò)setXXX形式綁定。另外,JdbcRowSet返回的結果默認是可以上下滾動(dòng)和可更新的,當然這需要數據庫廠(chǎng)商提供的JDBC Driver支持。下面的代碼演示了如何通過(guò)set方法設定數據庫連接參數,以及如何操作JdbcRowSet對象。
public static void testJdbcRowSet() { JdbcRowSetImpl jrs = new JdbcRowSetImpl(); try { // 設置連接數據庫的URL jrs.setUrl(DB2URL); // 設置連接數據庫的用戶(hù)名 jrs.setUsername(DB2USER); // 設置連接數據庫的密碼 jrs.setPassword(DB2PASSWORD); // 設置執行數據庫的SQL語(yǔ)句 jrs.setCommand("select * from student"); // 執行操作 jrs.execute(); // 對獲得的JdbcRowSet進(jìn)行操作 operateOnRowSet(jrs); // 關(guān)閉JdbcRowset jrs.close(); } catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } public static void operateOnRowSet(RowSet rs) { // 為RowSet注冊監聽(tīng)器 MyRowsetListener myListener = new MyRowsetListener(); rs.addRowSetListener(myListener); // 操作RowSet數據 try { // 遍歷讀取數據 while (rs.next()) { String id = rs.getString("ID");//$NON-NLS-1$ String name = rs.getString("NAME");//$NON-NLS-1$ System.out.println("ID=" + id + ",NAME=" + name);//$NON-NLS-1$ } } catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } |
其運行結果如下:
cursor moved ID=0011,NAME=zhou cursor moved ID=0021,NAME=zhang cursor moved |
FilteredRowSet
FilteredRowSet接口中規定了可以設定過(guò)濾器,其過(guò)濾接口為Predicate接口,必須實(shí)現Predicate接口中的evaluate方法。具體的代碼如下:
public static void testFilteredRowSet() { try { // 獲得數據庫連接 Connection conn = DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD); Statement stmt = conn.createStatement(); // 查詢(xún)數據庫,獲得表數據 ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$ FilteredRowSet frs = new FilteredRowSetImpl(); frs.populate(rs); // 設置過(guò)濾器 MyDBFilter filter = new MyDBFilter(11, 100); frs.setFilter(filter); operateOnRowSet(frs); // 關(guān)閉FilteredRowSet frs.close(); // 關(guān)閉與數據庫的連接 conn.close(); } catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } public static void operateOnRowSet(RowSet rs) { // 為RowSet注冊監聽(tīng)器 System.out.println("operateOnRowSet!");//$NON-NLS-1$ MyRowsetListener myListener = new MyRowsetListener(); rs.addRowSetListener(myListener); // 操作RowSet數據 try { // 遍歷讀取數據 while (rs.next()) { String id = rs.getString("ID");//$NON-NLS-1$ String name = rs.getString("NAME");//$NON-NLS-1$ System.out.println("ID=" + id + ",NAME=" + name);//$NON-NLS-1$ } } catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } public static void main(String[] args) { try { Class.forName(DB2DRIVER).newInstance(); } catch (InstantiationException e) { System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$ } catch (IllegalAccessException e) { System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$ } catch (ClassNotFoundException e) { System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$ } testFilteredRowSet(); } |
其中MyDBFilter實(shí)現了Predicate接口,其實(shí)現代碼如下:
class MyDBFilter implements Predicate { private int low; private int high; public MyDBFilter(int low, int high) { this.low = low; this.high = high; } public boolean evaluate(RowSet rs) { CachedRowSet crs=(CachedRowSet)rs; //如果id在low和high之間返回真 try { String id = (String) crs.getString("id"); int idValue = Integer.parseInt(id); if (low < idValue && idValue < high) { return true; } } catch (SQLException e) { } return false; } public boolean evaluate(Object arg0, int arg1) throws SQLException { return false; } public boolean evaluate(Object arg0, String arg1) throws SQLException { return false; } } |
其運行結果如下:
cursor moved ID=0021,NAME=zhang cursor moved |
JoinRowSet
JoinRowSet可以將多個(gè)RowSet對象進(jìn)行join合并,Join的列可以通過(guò)每個(gè)RowSet通過(guò)調用setMatchColumn方法來(lái)設置。setMatchColumn方式是Joinable接口定義的方法,五種類(lèi)型的RowSet規定都需要實(shí)現該接口。下面的代碼演示將student表和intern表中id相同的數據進(jìn)行join操作。JoinRowSet不需要保持與數據庫的連接。
public static void testJoinRowSet(){ Connection conn = null; try { JoinRowSet jrs = new JoinRowSetImpl(); // 獲得數據庫連接 conn = DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD); Statement stmt = conn.createStatement(); // 查詢(xún)數據庫,獲得表數據 ResultSet rs1 = stmt.executeQuery("select id,name from student");//$NON-NLS-1$ // 根據ResultSet對象生成CachedRowSet類(lèi)型的對象 CachedRowSetImpl crs1 = new CachedRowSetImpl(); crs1.populate(rs1); crs1.setMatchColumn(1); // 關(guān)閉ResultSet jrs.addRowSet(crs1); rs1.close(); // 查詢(xún)數據庫,獲得表數據 ResultSet rs2 = stmt.executeQuery("select id,company from intern");//$NON-NLS-1$ // 根據ResultSet對象生成CachedRowSet類(lèi)型的對象 CachedRowSetImpl crs2 = new CachedRowSetImpl(); crs2.populate(rs2); crs2.setMatchColumn(1); // 關(guān)閉ResultSet rs2.close(); // 將Result2放入JoinRowSet中進(jìn)行Join操作 jrs.addRowSet(crs2); // 關(guān)閉數據庫連接 conn.close(); while (jrs.next()) { String id = jrs.getString(1); String name = jrs.getString(2); String company = jrs.getString(3); //$NON-NLS-1$ System.out.println("ID=" + id + ",NAME=" + name+",COMPNAY="+company); } } catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } } |
其輸出結果為
ID=001111,NAME=zhou,COMPNAY=companyA |
WebRowSet
WebRowSet繼承自CachedRowSet,支持XML格式的查詢(xún),更新等操作,下面的代碼將WebRowSet對象輸出成XML格式到文件。
public static void testWebRowSet(){ try { // 獲得數據庫連接 Connection conn = DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD); Statement stmt = conn.createStatement(); // 查詢(xún)數據庫,獲得表數據 ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$ WebRowSetImpl wrs = new WebRowSetImpl(); wrs.populate(rs); FileOutputStream out = new FileOutputStream("data.xml"); wrs.writeXml(out); wrs.close(); // 關(guān)閉與數據庫的連接 conn.close(); } catch (SQLException e) { System.out.println("Andrew: SQLException!");//$NON-NLS-1$ e.printStackTrace(); } catch(IOException e){ System.out.println("Andrew: IOException!");//$NON-NLS-1$ e.printStackTrace(); } } |
其運行結果data.xml大致如下:
<?xml version="1.0"?> XML文件屬性格式 …… <metadata> <column-count>2</column-count> <column-definition> <column-index>1</column-index> <auto-increment>false</auto-increment> <case-sensitive>true</case-sensitive> <currency>false</currency> <nullable>0</nullable> <signed>false</signed> <searchable>true</searchable> <column-display-size>10</column-display-size> <column-label>ID</column-label> <column-name>ID</column-name> <schema-name>ZHOUDP </schema-name> <column-precision>10</column-precision> <column-scale>0</column-scale> <table-name>STUDENT</table-name> <catalog-name>TEST</catalog-name> <column-type>12</column-type> <column-type-name>VARCHAR</column-type-name> </column-definition> <column-definition> <column-index>2</column-index> <auto-increment>false</auto-increment> <case-sensitive>true</case-sensitive> <currency>false</currency> <nullable>1</nullable> <signed>false</signed> <searchable>true</searchable> <column-display-size>50</column-display-size> <column-label>NAME</column-label> <column-name>NAME</column-name> <schema-name>ZHOUDP </schema-name> <column-precision>50</column-precision> <column-scale>0</column-scale> <table-name>STUDENT</table-name> <catalog-name>TEST</catalog-name> <column-type>12</column-type> <column-type-name>VARCHAR</column-type-name> </column-definition> </metadata> <data> <currentRow> <columnValue>0011</columnValue> <columnValue>zhou</columnValue> </currentRow> <currentRow> <columnValue>0021</columnValue> <columnValue>zhang</columnValue> </currentRow> </data> </webRowSet> |
關(guān)于作者