1. 程式人生 > >Rowset 的介面及其子介面的用法

Rowset 的介面及其子介面的用法

  在jdk1.4的javax.sql包中有一個RowSet介面,但是沒有具體實現的類。”Tiger”誕生之後,引入了javax.sql.rowset包中的五個子介面和com.sun.rowset包裡面的對應的五個實現類,這樣我們就可是使用功能強大的RowSet了。jdk1.5中RowSet的五個子介面分別是JdbcRowSet,CachedRowSet,WebRowSet,JoinRowSet和FilteredRowSet,他們為我們的資料庫開發帶來了強大的功能和方便的操作。

[被遮蔽廣告]  java執行環境是:RedHat 9
  Jdk 1.5.1_01
  Eclipse 3.1m4
  MySql 4.1.10 (JDBC Driver:org.gjt.mm.mysql.Driver)

  首先在test資料庫裡面建立了兩個表用於這次的學習,下面是指令碼:

create table table1 (id int not null , name varchar(20) not null);
  create table table2 (id int not null, info varchar(20) not null);



  然後我就插入了一些資料用於測試。以下內容以我的環境示意,大家只要修改相應地方就可用於自己的測試。

  RowSet物件可分為兩類:有連線的和無連線的。JdbcRowSet是唯一一個有連線的實現,和傳統的ResultSet一個樣,有連線的實現是基於Jdbc驅動的連線,資料庫的連線是貫穿整個對資料庫的操作。而無連線的實現是基於Reader和Writer流的連線,在需要讀取資料和寫入資料的時候才建立連線,在整個操作過程中都是斷開連線的,後面四個介面物件都是無連線的實現。下面我就針對每一個介面來介紹一下它們各自的功能。

JdbcRowSet介面:


  我的理解是這個介面基本上和ResultSet有類似的功能,只不過它的結果集預設是ResultSet.TYPE_SCROLL_INSENSITIVE和ResultSet.CONCUR_UPDATABLE的,也就是說預設的結果集就是可以上下滾動和可更新的。

  因為本身RowSet介面就是ResultSet的子介面,所以1.5裡面的所有RowSet都有ResultSet的方法,而JdbcRowSet又只是在預設的屬性和ResultSet有區別,所以它對結果集的操作方法和ResultSet都是一樣的,我就不具體介紹了,大家可以參考API。

  下面我介紹一下JdbcRowSet的建立方法,這有兩種方法,一種是基於傳統的JDBC連線資料庫的方法:


  

Class.forName(“org.gjt.mm.mysql.Driver”);
  Connection conn=DriverManager.getConnection(“jdbc:mydql://localhost:3306/test”,”root’,””);
  Statement stmt=conn.createStatement();
  ResultSet rs=stamt.executeQuery(“select * from table1”);
  JdbcRowSet jrs=new JdbcRowSetImpl(rs);



  這樣就建立了一個物件(JdbcRowSetImpl是com.sun.rowset包裡面的實現類,文中的五個介面在包中都對應有一個實現類),這個物件裡面的資料就是和rs裡面的資料是一樣的。還有一種建立的方法是使用預設的構造方法,然後set屬性得到資料,個人推薦使用第二種方法:

  

JdbcRowSet jrs=new JdbcRowSetImpl();
  jrs.setUrl(“jdbc:mydql://localhost:3306/test”);
  jrs.setUsername(“root”);
  jrs.setPassword(“”);
  jrs.setCommand(“select * from table1”);
  jrs.execute();



  這樣建立的物件是和第一種方法是一樣的結果。當然這種方法可以連線一個數據源,如果我們在上下文環境種綁定了一個數據源,JNDI名字是dataSource1,那麼下面的程式碼就可以獲得物件:

  

JdbcRowSet jrs=new JdbcRowSetImpl();
  jrs.setDataSourceName(“dataSource1”)
  jrs.execute();



  得到物件之後我們就可以使用相應的方法來對資料進行遍歷,更新,插入或者刪除。

  有2點要說明:第一,其它四個介面的物件中除了JoinRowSet建立方式基本都是一樣的,只是介面名字和介面實現類的名字不同而已,後面我就不再說明建立物件的方法了。第二,雖然JdbcRowSet預設是可滾動和可更新的,但是這也是需要資料庫驅動支援的,我使用的MySql驅動就不支援更新結果集,所以大家使用之前需要閱讀驅動的說明文件。

CachedRowSet介面:

  它繼承於RowSet介面,而且他是無連線的RowSet的其他3個實現的父介面,也就是說其他3個介面都直接或者間接繼承了它。從名字我們可以知道,它的原理就是讀入資料儲存在快取進行相應的操作。

  建立介面物件除了上面的兩種建立方式,還有一個方法,就是在構造方法裡面傳遞一個SyncProvider。之前我說過無連線的RowSet都是基於流讀寫的,那麼這裡所說的SyncProvider就是提供了特定的Reader和Writer。jdk1.5文件的Sample Coder有這樣的實現:

  

String provider= “com.fred.providers.HighAvailabilityProvider”
  CachedRowSet crs=new CachedRowSetImpl(provider);



  這樣我們就為RowSet設定了特定的Reader和Writer,但是這是需要第三方的包支援的。而我們使用無參的構造方法建立的物件是使用了預設的SyncProvider,當然一般來說這對於我們就已經足夠了。建立了物件之後就可以使用和JdbcRowSet一樣的方法來進行就結果集的增刪改操作了,但是唯一不同的就是在更新了結果集之後必須呼叫Writer將快取中的資料寫入資料庫,而其方法就是crs.acceptChages();

  CachedRowSet提供的最令人興奮的功能就是分頁功能。以前程式設計師很頭疼的問題就是怎麼處理資料分頁而不影響效能,現在有了CachedRowSet一切都變得那麼簡單,請看下面的程式碼:

  

CachedRowSet crs=new CaehedRowSetImpl();
  crs.setUrl(“jdbc:mydql://localhost:3306/test”);
  crs.setUsername(“root”);
  crs.setPassword(“”);
  crs.setCommand(“select * from table1”);
  crs.setPageSize(5);
  crs.execute();
  while(crs.nextPage())
  while(crs.next())
  System.out.println(crs.getInt(“id”+”/t/t”+crs.getString(“name”));



  我們在crs.execute()之前設定每頁的資料行數,那麼Reader讀取資料的時候就只讀指定的行數的資料,這樣我們就避免了一次讀取所有資料再進行分頁操作。是不是很簡單呢?

JoinRowSet介面:

  這個介面可以提供我們在無連線的狀態下直接對結果集進行Join。下面的程式碼提供了JoinRowSet的實現:

  

CachedRowSet crs1=new CaehedRowSetImpl();
  crs1.setUrl(“jdbc:mydql://localhost:3306/test”);
  crs1.setUsername(“root”);
  crs1.setPassword(“”);
  crs1.setCommand(“select * from table1”);
  crs1.execute();
  CachedRowSet crs2=new CaehedRowSetImpl();
  crs2.setUrl(“jdbc:mydql://localhost:3306/test”);
  crs2.setUsername(“root”);
  crs2.setPassword(“”);
  crs2.setCommand(“select * from table2”);
  crs2.execute();
  JoinRowSet jrs=new JoinRowSetImpl();
  jrs.addRowSet(crs1,”id”);
  jrs.addRowSet(crs2,”id”);
  while(jrs.next())
  System.out.println(jrs.getInt(“id”)+”/t/t”+jrs.getString(“name”)+”/t/t”+jrs.getString(“info”);



  這段程式碼的作用和執行select * from table1 inner join table2 on table1.id=table2.id語句得到的結果集是一樣的。但是我個人認為與其這樣複雜地使用JoinRowSet,不如直接使用這條Join語句來得到CachedRowSet。

  預設的Join是inner join的,介面還支援cross join,full join,left outer join和right outer join,我們通過setJoinType()方法來修改連線型別,當然這還是需要資料庫的支援。還有一個值得注意的地方就是,在這個例子裡我連線的列在兩個表裡面都叫id,那麼我們取資料的時候就使用id這個名字,那如果兩列的名字不一樣呢?系統就會為這個連線列取一個預設的名字叫做”MergedCol”。

FilteredRowSet介面:

  .NET的ADO.NET支援獲取結果集使用一定的條件過濾從而得到不同的結果,那現在jdk1.5也能做到了,FilterRowSet介面讓我們可以靈活地定義過濾條件達到不同的效果。Javax.sql.rowset包裡面的Predicate介面就是這個過濾器,我們通過實現這個介面定義過濾條件,下面是示意程式碼:

  

public class Filter implements Predicate {
  private int min;
  private int max;
  private String colName;
  public Filter (int min ,int max ,String colName)
  {
   this.min=min; this.max=max; this.colName=colName;
  }
  public boolean evaluate (RowSet rs) {
  CachedRowSet crs=(CachedRowSet)rs;
  if((crs.getInt(colName)>min)&& (crs.getInt(colName)   return true;
else return false;
  }
  }



  下面我們就使用這個過濾器來過濾掉id不在min和max之間的資料:

  

FilteredRowSet frs=new FilteredRowSet();
  ……
  frs.setCommand(“select * from table1”);
  frs.execute();//先獲取所有資料;
  frs.setFilter(new Filter(1,20,”id”);//過濾掉id值不在1和20之間的資料;



  因為實現Prdicate接口裡面的方法很靈活,所以我們就能很靈活地設定過濾條件,我們就可以只通過一條語句得到不同的結果。

WebRowSet介面:

  XML因為其平臺無關性越來越受到開發者的青睞,它也是資料持久化的一個不錯的選擇,WebRowSet封裝了讀寫XML的方法,我們就可以輕鬆地把資料庫的資料持久化到XML或者從XML讀取資料寫入資料庫。

  寫入到XML檔案的方法是wrs.writeXML(new FileOutputStream(“data.xml”));它執行的結果是把記憶體中的資料寫入當前目錄裡面的data.xml檔案中。在這個xml檔案裡面記錄了三類資料:

  properties:包括setXXX()方法所有的屬性,沒有設定的就是預設屬性

  metadata:包括資料庫表的相關元資料,對應ResultSetMetaData裡的資訊

  data:結果集的全部資料,從xml檔案讀取資料裝載到RowSet的方法是readXML(…);只要是按照規範的格式寫的xml都可以裝載進來。