13.6.2 离线RowSet
在使用ResultSet
的时代,程序查询得到ResultSet
之后必须立即读取或处理它对应的记录,否则旦Connection
关闭,再去通过ResultSet
读取记录就会引发异常。在这种模式下,JDBC
编程十分痛苦.
假设应用程序架构被分为两层:数据访问层和视图显示层,当应用程序在数据访问层查询得到ResultSet
之后,对ResultSet
的处理有如下两种常见方式。
1.使用迭代访问ResultSet
里的记录,并将这些记录转换成Java Bean
,再将多个Java Bean
封装成个List
集合,也就是完成”ResultSet
到Java Bean
集合”的转换。转换完成后可以关闭Connection
等资源,然后将Java bean
集合传到视图显示层,视图显示层可以显示查询得到的数据。
2.直接将ResultSet
传到视图显示层——这要求当视图显示层显示数据时,底层Connection
必须直处于打开状态,否则ResultSet
无法读取记录。
第一种方式比较安全,但编程十分烦琐;
第二种方式则需要Connection
一直处于打开状态,这不仅不安全,而且对程序性能也有较大的影响。
通过使用离线RowSet
可以十分”优雅”地处理上面的问题,离线RowSet
会直接将底层数据读入内存中,封装成RowSet
对象,而RowSet
对象则完全可以当成Java Bean
来使用。因此不仅安全,而且编程十分简单。CachedRowSet
是所有离线RowSet
的父接口,因此下面以CachedRowSet
为例进行介绍。看下面程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| import java.util.*; import java.io.*; import java.sql.*; import javax.sql.*; import javax.sql.rowset.*;
public class CachedRowSetTest { private static String driver; private static String url; private static String user; private static String pass; public void initParam(String paramFile) throws Exception { Properties props = new Properties(); props.load(new FileInputStream(paramFile)); driver = props.getProperty("driver"); url = props.getProperty("url"); user = props.getProperty("user"); pass = props.getProperty("pass"); }
public CachedRowSet query(String sql) throws Exception { Class.forName(driver); Connection conn = DriverManager.getConnection(url, user, pass); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); RowSetFactory factory = RowSetProvider.newFactory(); CachedRowSet cachedRs = factory.createCachedRowSet(); cachedRs.populate(rs); rs.close(); stmt.close(); conn.close(); return cachedRs; } public static void main(String[] args) throws Exception { CachedRowSetTest ct = new CachedRowSetTest(); ct.initParam("mysql.ini"); CachedRowSet rs = ct.query("select * from student_table"); rs.afterLast(); while (rs.previous()) { System.out.println(rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3)); if (rs.getInt("student_id") == 3) { rs.updateString("student_name", "孙悟空"); rs.updateRow(); } } Connection conn = DriverManager.getConnection(url, user, pass); conn.setAutoCommit(false); rs.acceptChanges(conn); } }
|
上面程序中的①号代码调用了RowSet
的populate(ResultSet rs)
方法来包装给定的ResultSet
,接下来的粗体字代码关闭了ResultSet
、 Statement
、 Connection
等数据库资源。如果程序直接返回ResultSet
,那么这个ResultSet
无法使用:这是因为底层的Connection
已经关闭了;但程序返回的是CachedRowSet
,它是一个离线RowSet
,因此程序依然可以读取、修改RowSet
中的记录。
运行该程序,可以看到在Connection
关闭的情况下,程序依然可以读取、修改RowSet
里的记录.
为了将程序对离线RowSet
所做的修改同步到底层数据库,程序在调用RowSet
的acceptChanges()
方法时必须传入Connection
.
原文链接: 13.6.2 离线RowSet