RowSet概念
在C#中,提供了一個DataSet,可以把數據庫的數據放在內存中進行離線操作(讀寫),操作完成之后再同步到數據庫中去,Java中則提供了類似的功能RowSet.
RowSet接口繼承自ResultSet接口。與ResultSet相比,RowSet默認是可滾動、可更新、可序列化的結果集,可以作為JavaBean來方便地在網絡上傳輸,用於同步兩端數據。對於離線RowSet而言,
程序從創建RowSet時就已經把數據load進內存,因此可以更好地利用內存性能,降低數據庫服務器的負載,提高程序性能。
RowSet接口下包含了JdbcRowSet, CachedRowSet, FilteredRowSet, JoinRowSet, WebRowSet,除了JdbcRowSet之外,后面四個都是離線RowSet,它們之間的繼承關系如下,
RowSetFactory
在JDK1.6及以前的版本中,如果要使用JdbcRowSet,則必須使用JdbcRowSetImpl的構造器來構造對象,但是在編譯的時候會有警告,因此JdbcRowSetImpl是內部專用的API,在未來版本可能會刪除。這種獲取JdbcRowSet的方式是不推薦的,因為使用內部API,在將來的版本中可能不兼容,而且這樣的程序直接與具體的實現類JdbcRowSetImpl耦合,不利於維護和升級。
在JDK1.7中,這個問題得到了改善。JDK1.7引入了RowSetFactory和RowSetProvider接口,其中RowSetProvider負責創建RowSetFactory,而RowSetFactory則可以通過以下方法創建RowSet實例,
- createCachedRowSet()
- createFilteredRowSet()
- createJdbcRowSet()
- createJoinRowSet()
- createWebRowSet()
通過RowSetFactory,程序就可以與RowSet的實現類分離,避免了直接使用具體的實現類JdbcRowSetImpl。
創建對象時可以傳入ResultSet實例填充RowSet,也可以在創建JdbcRowSet實例之后通過execute(sql)方法得到數據填充RowSet,
下面演示使用RowSetFactory和RowSetProvider接口獲取RowSet實例並使用的方法,
1 package db; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.IOException; 6 import java.sql.Connection; 7 import java.sql.DriverManager; 8 import java.sql.SQLException; 9 import java.util.Properties; 10 11 import javax.sql.rowset.JdbcRowSet; 12 import javax.sql.rowset.RowSetFactory; 13 import javax.sql.rowset.RowSetProvider; 14 15 16 public class RowSetFactoryTest { 17 private String driver; 18 private String url; 19 private String user; 20 private String pass; 21 public void initParam(String paramFile) throws FileNotFoundException, IOException, ClassNotFoundException { 22 //用Properties類加載屬性文件 23 Properties prop = new Properties(); 24 prop.load(new FileInputStream(paramFile)); 25 driver = prop.getProperty("driver"); 26 url = prop.getProperty("url"); 27 user = prop.getProperty("user"); 28 pass = prop.getProperty("pass"); 29 Class.forName(driver); 30 } 31 32 public void update(String sql) throws SQLException { 33 RowSetFactory factory = RowSetProvider.newFactory(); 34 35 try ( 36 //使用RowSet的execute方式返回數據,則不再需DriverManager連接數據庫了 37 //Connection conn = DriverManager.getConnection(url, user, pass); 38 /* 39 * for JDK1.6 40 * JdbcRowSet jdbcRs = new JdbcRowSetImpl(conn); 41 */ 42 // for JDK 1.7 43 JdbcRowSet jdbcRs = factory.createJdbcRowSet(); 44 ) { 45 jdbcRs.setUrl(url); 46 jdbcRs.setUsername(user); 47 jdbcRs.setPassword(pass); 48 jdbcRs.setCommand(sql); 49 jdbcRs.execute(); 50 51 jdbcRs.afterLast(); 52 //向前滾動結果集 53 while(jdbcRs.previous()) { 54 System.out.println(jdbcRs.getInt(1)+"\t"+jdbcRs.getString(2)+"\t"+jdbcRs.getString(3)); 55 56 if (jdbcRs.getInt("jdbc_id") == 3) { 57 //修改指定行記錄,因為 JdbcRowSet 繼承自 ResultSet, 所以修改記錄的方式也一樣 58 jdbcRs.updateString("jdbc_name", "小明"); 59 jdbcRs.updateRow(); 60 System.out.println("修改成功: "); 61 System.out.println(+jdbcRs.getInt(1)+"\t"+jdbcRs.getString(2)+"\t"+jdbcRs.getString(3)); 62 } 63 64 } 65 } 66 } 67 68 public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException, IOException, SQLException { 69 RowSetFactoryTest jt = new RowSetFactoryTest(); 70 jt.initParam("mysql.ini"); 71 jt.update("select * from jdbc_test"); 72 } 73 }
執行上面程序會發現第3行被修改了,需要注意的是JdbcRowSet並不是離線的RowSet,因此需要在數據庫保持連接的情況下才能修改數據
因為JdbcRowSet接口繼承自ResultSet,所以修改數據的方法跟ResultSet一樣的。 程序執行結果如下,

1 27 學生名27 學生名28 2 26 學生名26 學生名27 3 25 學生名25 學生名26 4 24 學生名24 學生名25 5 23 學生名23 學生名24 6 22 學生名22 學生名23 7 21 學生名21 學生名22 8 20 學生名20 學生名21 9 19 學生名19 學生名20 10 18 學生名18 學生名19 11 17 學生名17 學生名18 12 16 學生名16 學生名17 13 15 學生名15 學生名16 14 14 學生名14 學生名15 15 13 學生名13 學生名14 16 12 學生名12 學生名13 17 11 學生名11 學生名12 18 10 學生名10 學生名11 19 9 學生名9 學生名10 20 8 學生名8 學生名9 21 7 學生名7 學生名8 22 6 學生名6 學生名7 23 5 學生名5 學生名6 24 4 學生名4 學生名5 25 3 小明 小強 26 修改成功: 27 3 小明 小強 28 2 學生名2 學生名3 29 1 學生名1 學生名2