2006 年 4 月 10 日
Java 5 在 Java Database Connectivity (JDBC) 方面加強了支持,其中加入了新的包 javax.sql.rowset,javax.sql.rowset.serial,javax.sql.rowset.spi。本文將通過實例來演示這些新的特性。
RowSet 新特性簡介
Java 5在Java Database Connectivity (JDBC)方面加強了支持,其中加入了新的包javax.sql.rowset,javax.sql.rowset.serial,javax.sql.rowset.spi。從RowSet接口繼承規定了五個新的接口:
1. CachedRowSet: CachedRowset可以不用與數據源建立長期的連接,只有當從數據庫讀取數據或是往數據庫寫入數據的時候才會與數據庫建立連接,它提供了一種輕量級的訪問數據庫的方式,其數據均存在內存中。
2. JdbcRowSet:對ResultSet的對象進行包裝,使得可以將ResultSet對象做為一個JavaBeans ? 組件。
3. FilteredRowSet:繼承自CachedRowSet,可以根據設置條件得到數據的子集。
4. JoinRowSet:繼承自CachedRowSet,可以將多個RowSet對象進行SQL Join語句的合并。
5. WebRowSet:繼承自CachedRowSet,可以將WebRowSet對象輸出成XML格式。
下面分別演示如何使用這五個新接口。
實驗環境
IBM DB2 Universal 8.1
數據庫名:DemoDB
數據庫用戶名:db2admin
數據庫密碼:password
CachedRowSet
CachedRowSet可以通過調用populate(ResuletSet rs)來生成數據,一旦獲得數據,CachedRowSet就可以斷開與數據庫的連接,直到往數據庫寫入數據的時候才需建立連接。
可以使用自己擴展的或是使用Reference Implement的實現類進行訪問數據庫。下面的代碼演示了如何根據ResultSet建立一個CachedRowSet對象,在中斷與數據庫連接的情況下,讀取數據,并做更新,最后再獲取數據庫連接,將更新落實到數據庫中。
public static void testCachedRowSet(){
Connection conn = null;
try {
// 獲得數據庫連接
conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD);
Statement stmt = conn.createStatement();
// 查詢數據庫,獲得表數據
ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$
// 根據ResultSet對象生成CachedRowSet類型的對象
CachedRowSetImpl crs = new CachedRowSetImpl();
crs.populate(rs);
// 關閉ResultSet
rs.close();
// 關閉數據庫的連接
conn.close();
// 在中斷與數據庫連接的情況下,對CachedRowSet進行操作
operateOnRowSet(crs);
// 重新獲取與數據庫的連接
conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD);
// 將CachedRowSet的內容更新到數據庫
crs.acceptChanges(conn);
// 關閉CachedRowSet
crs.close();
// 關閉數據庫連接
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允許注冊監聽器,可以在光標移動,RowSet發生改變時觸發。其具體代碼如下:
public static void operateOnRowSet(RowSet rs){
// 為RowSet注冊監聽器
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{
// 光標發生移動
public void cursorMoved(RowSetEvent event) {
System.out.println("cursor moved");
}
// row發生改變
public void rowChanged(RowSetEvent event) {
System.out.println("row changed");
}
// RowSet發生改變
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類似,與CachedRowSet不同,JdbcRowSet在操作時保持與數據庫的連接??梢詫⑴c數據庫連接的URL,用戶名,密碼以及執行的SQL語句通過setXXX形式綁定。另外,JdbcRowSet返回的結果默認是可以上下滾動和可更新的,當然這需要數據庫廠商提供的JDBC Driver支持。下面的代碼演示了如何通過set方法設定數據庫連接參數,以及如何操作JdbcRowSet對象。
public static void testJdbcRowSet() {
JdbcRowSetImpl jrs = new JdbcRowSetImpl();
try {
// 設置連接數據庫的URL
jrs.setUrl(DB2URL);
// 設置連接數據庫的用戶名
jrs.setUsername(DB2USER);
// 設置連接數據庫的密碼
jrs.setPassword(DB2PASSWORD);
// 設置執行數據庫的SQL語句
jrs.setCommand("select * from student");
// 執行操作
jrs.execute();
// 對獲得的JdbcRowSet進行操作
operateOnRowSet(jrs);
// 關閉JdbcRowset
jrs.close();
} catch (SQLException e) {
System.out.println("Andrew: SQLException!");//$NON-NLS-1$
e.printStackTrace();
}
}
public static void operateOnRowSet(RowSet rs) {
// 為RowSet注冊監聽器
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接口中規定了可以設定過濾器,其過濾接口為Predicate接口,必須實現Predicate接口中的evaluate方法。具體的代碼如下:
public static void testFilteredRowSet() {
try {
// 獲得數據庫連接
Connection conn = DriverManager.getConnection(DB2URL, DB2USER,
DB2PASSWORD);
Statement stmt = conn.createStatement();
// 查詢數據庫,獲得表數據
ResultSet rs = stmt.executeQuery("select * from student");//$NON-NLS-1$
FilteredRowSet frs = new FilteredRowSetImpl();
frs.populate(rs);
// 設置過濾器
MyDBFilter filter = new MyDBFilter(11, 100);
frs.setFilter(filter);
operateOnRowSet(frs);
// 關閉FilteredRowSet
frs.close();
// 關閉與數據庫的連接
conn.close();
} catch (SQLException e) {
System.out.println("Andrew: SQLException!");//$NON-NLS-1$
e.printStackTrace();
}
}
public static void operateOnRowSet(RowSet rs) {
// 為RowSet注冊監聽器
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實現了Predicate接口,其實現代碼如下:
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可以將多個RowSet對象進行join合并,Join的列可以通過每個RowSet通過調用setMatchColumn方法來設置。setMatchColumn方式是Joinable接口定義的方法,五種類型的RowSet規定都需要實現該接口。下面的代碼演示將student表和intern表中id相同的數據進行join操作。JoinRowSet不需要保持與數據庫的連接。
public static void testJoinRowSet(){
Connection conn = null;
try {
JoinRowSet jrs = new JoinRowSetImpl();
// 獲得數據庫連接
conn = DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD);
Statement stmt = conn.createStatement();
// 查詢數據庫,獲得表數據
ResultSet rs1 = stmt.executeQuery("select id,name from student");//$NON-NLS-1$
// 根據ResultSet對象生成CachedRowSet類型的對象
CachedRowSetImpl crs1 = new CachedRowSetImpl();
crs1.populate(rs1);
crs1.setMatchColumn(1);
// 關閉ResultSet
jrs.addRowSet(crs1);
rs1.close();
// 查詢數據庫,獲得表數據
ResultSet rs2 = stmt.executeQuery("select id,company from intern");//$NON-NLS-1$
// 根據ResultSet對象生成CachedRowSet類型的對象
CachedRowSetImpl crs2 = new CachedRowSetImpl();
crs2.populate(rs2);
crs2.setMatchColumn(1);
// 關閉ResultSet
rs2.close();
// 將Result2放入JoinRowSet中進行Join操作
jrs.addRowSet(crs2);
// 關閉數據庫連接
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格式的查詢,更新等操作,下面的代碼將WebRowSet對象輸出成XML格式到文件。
public static void testWebRowSet(){
try {
// 獲得數據庫連接
Connection conn = DriverManager.getConnection(DB2URL, DB2USER,
DB2PASSWORD);
Statement stmt = conn.createStatement();
// 查詢數據庫,獲得表數據
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();
// 關閉與數據庫的連接
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>
|