⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cachedrowset.htm

📁 Sun的高速缓存CachedRowSet方案资料档
💻 HTM
📖 第 1 页 / 共 5 页
字号:
        int id = crs.getInt("ID");
        Clob comment = crs.getClob("COM");
        short dept = crs.getShort("DEPT");
        System.out.println(name + "  " + id + "  " + comment + "  " + dept);
    }
 </PRE>
<H4>2.1 检索 <CODE>RowSetMetaData</CODE></H4>通过在 <CODE>RowSetMetaData</CODE> 对象上调用 
<CODE>ResultSetMetaData</CODE> 和 <CODE>RowSetMetaData</CODE> 的方法,应用程序可以获得有关 
<CODE>CachedRowSet</CODE> 对象中各列的信息。以下代码片断(其中 <I>crs</I> 是一个 
<CODE>CachedRowSet</CODE> 对象)展示了该过程。第一行使用关于 <I>crs</I> 中各列的信息创建一个 
<CODE>RowSetMetaData</CODE> 对象。继承自 <CODE>ResultSet</CODE> 接口的方法 
<CODE>getMetaData</CODE> 返回一个 <CODE>ResultSetMetaData</CODE> 对象,将该对象分配给变量 
<I>rsmd</I> 前会将其强制转换为 <CODE>RowSetMetaData</CODE> 对象。第二行查明 <I>jrs</I> 
的列数,第三行获得存储在 <CODE>jrs</CODE> 第二列中 JDBC 类型的值。 <PRE>     RowSetMetaData rsmd = (RowSetMetaData)crs.getMetaData();
     int count = rsmd.getColumnCount();
     int type = rsmd.getColumnType(2);
 </PRE><CODE>RowSetMetaData</CODE> 接口与 <CODE>ResultSetMetaData</CODE> 接口有两方面不同。 
<UL>
  <LI><I>它包括<CODE>设置</CODE>方法:</I>当使用取自不同 <CODE>ResultSet</CODE> 对象的数据填充 
  <CODE>RowSet</CODE> 对象时,该 RowSet 对象在内部使用这些方法。 
  <P></P>
  <LI><I>它包含较少的<CODE>获取</CODE>方法:</I>某些 <CODE>ResultSetMetaData</CODE> 方法无法应用到 
  <CODE>RowSet</CODE> 对象。例如,不会应用那些检索某个列值是可写入的还是只读的方法,因为 <CODE>RowSet</CODE> 
  对象的所有列要么是可写入的,要么是只读的,这取决于该 rowset 是否可更新。 </LI></UL>注:要返回 
<CODE>RowSetMetaData</CODE> 对象,实现必须重写 <CODE>java.sql.ResultSet</CODE> 中定义的 
<CODE>getMetaData()</CODE> 方法返回 <CODE>RowSetMetaData</CODE> 对象。 
<H3>3.0 更新 <CODE>CachedRowSet</CODE> 对象</H3>更新 <CODE>CachedRowSet</CODE> 对象与更新 
<CODE>ResultSet</CODE> 对象类似,但是因为更新 rowset 
时它并未连接到其数据源,所以必须执行额外的步骤才能使更改在底层数据源中生效。调用方法 <CODE>updateRow</CODE> 或 
<CODE>insertRow</CODE> 后,<CODE>CachedRowSet</CODE> 对象还必须调用方法 
<CODE>acceptChanges</CODE> 使更新写入数据源。以下示例(其中指针在 <CODE>CachedRowSet</CODE> 对象 
<I>crs</I> 中的行上)显示了更新当前行中两个列值并同样更新 <CODE>RowSet</CODE> 对象的底层数据源所需的代码。 <PRE>     crs.updateShort(3, 58);
     crs.updateInt(4, 150000);
     crs.updateRow();
     crs.acceptChanges();
 </PRE>
<P>下一个示例演示了移至插入行、在插入行上构建新行、将新行插入 rowset,然后调用方法 <CODE>acceptChanges</CODE> 
将新行添加到底层数据源。注意,与获取方法一样,更新方法可以采用列索引或列名来指定所操作的列。 <PRE>     crs.moveToInsertRow();
     crs.updateString("Name", "Shakespeare");
     crs.updateInt("ID", 10098347);
     crs.updateShort("Age", 58);
     crs.updateInt("Sal", 150000);
     crs.insertRow();
     crs.moveToCurrentRow();
     crs.acceptChanges();
 </PRE>
<P>注:<CODE>insertRow()</CODE> 方法在何处插入 <CODE>CachedRowSet</CODE> 
对象的插入行内容是由实现定义的。<CODE>CachedRowSet</CODE> 接口的参考实现紧随当前行插入新行,但也可以实现为在任何其他位置插入新行。 
<P>有关这些示例的另一个注意点是它们使用方法 <CODE>acceptChanges</CODE> 的方式。通过内部调用 
<CODE>RowSet</CODE> 对象的 writer 将这些更改写入数据源,从而将 <CODE>CachedRowSet</CODE> 
对象中的更改传播回底层数据源的正是此方法。为此,writer 不得不承受建立到数据源的连接所带来的开销。上述两个代码片断在调用 
<CODE>updateRow</CODE> 或 <CODE>insertRow</CODE> 后立即调用方法 
<CODE>acceptChanges</CODE>。但是,如果更改了多个行,则更高效的做法是在调用所有 <CODE>updateRow</CODE> 和 
<CODE>insertRow</CODE> 后再调用 <CODE>acceptChanges</CODE>。如果只调用 
<CODE>acceptChanges</CODE> 一次,则只需要建立一个连接。 
<P>
<H3>4.0 更新底层数据源</H3>执行 <CODE>acceptChanges</CODE> 方法时,在后台调用 
<CODE>CachedRowSet</CODE> 对象的 writer(一个 <CODE>RowSetWriterImpl</CODE> 对象),以便将对 
rowset 所作的更改写入底层数据源。实现该 writer 以建立到数据源的连接并写入更新。 
<P>可通过 <CODE>SyncProvider</CODE> 接口的实现提供 writer,这已第 1 部分“创建 
<CODE>CachedRowSet</CODE> 对象”中讨论。默认的参考实现提供程序 <CODE>RIOptimisticProvider</CODE> 
会实现其 writer 使用乐观并发控制 (optimistic concurrency control) 机制。也就是说,在 rowset 
与数据库断开时它不对底层数据库维持任何锁定,在将数据写入数据源之前它只是检查是否有冲突。如果存在冲突,则不向数据源写入任何内容。 
<P><CODE>SyncProvider</CODE> 类提供的 reader/writer 
设施是可插入的,允许自定义数据的检索和更新。如果需要其他的并发控制机制,可使用方法 <CODE>setSyncProvider</CODE> 插入其他 
<CODE>SyncProvider</CODE> 实现。 
<P>要使用乐观并发控制例程,<CODE>RIOptismisticProvider</CODE> 
要同时维护其当前值及其原始值(刚好位于当前值之前的值)。注意,如果没有对 <CODE>RowSet</CODE> 
对象中的数据进行任何更改,则其当前值和原始值相同,都是最初填充 <CODE>RowSet</CODE> 对象时使用的值。但是,一旦更改了 
<CODE>RowSet</CODE> 对象中的任何值,当前值和原始值就不同了,尽管此时原始值仍是最初的值。随着后续对 <CODE>RowSet</CODE> 
对象中的数据进行更改,其原始值和当前值仍保持不同,但是其原始值将是前一个当前值。 
<P>关注原始值允许 writer 对 <CODE>RowSet</CODE> 对象的原始值和数据库中的值进行比较。如果数据库中的值与 
<CODE>RowSet</CODE> 对象的原始值不同,则意味着数据库中的值已经更改,出现了冲突。writer 
是否检查冲突、检查的程度如何,以及它如何处理冲突都取决于它的实现方式。 
<P>
<H3>5.0 注册和通知侦听器</H3>作为 JavaBeans 组件,参与 JavaBeans 事件模型的所有 rowset 
都继承了用来注册侦听器和用来通知这些侦听器 <CODE>BaseRowSet</CODE> 
类中发生更改的各种方法。<CODE>CachedRowSet</CODE> 对象的侦听器是一个组件,只要 rowset 中发生更改,它就应得到通知。例如,如果 
<CODE>CachedRowSet</CODE> 对象包含查询的结果,并且这些结果将以表格和条形图之类的形式显示,则可以向 rowset 
将该表格和条形图注册为侦听器,这样它们可以更新以反映各种更改。要成为侦听器,表格和条形图类必须实现 <CODE>RowSetListener</CODE> 
接口。然后可将它们添加到 <CODE>CachedRowSet</CODE> 对象的侦听器列表,如以下代码行所示。 <PRE> 
    crs.addRowSetListener(table);
    crs.addRowSetListener(barGraph);
 </PRE>每个移动指针或更改数据的 <CODE>CachedRowSet</CODE> 方法也将更改通知已注册的侦听器,所以当 
<CODE>crs</CODE> 中发生更改时 <CODE>table</CODE> 和 <CODE>barGraph</CODE> 将得到通知。 
<P>
<H3>6.0 向瘦客户端传递数据</H3>使用 <CODE>CachedRowSet</CODE> 
对象的主要原因之一是要在应用程序的不同组件之间传递数据。因为 <CODE>CachedRowSet</CODE> 
对象是可序列化的,所以可使用它(举例来说)将运行于服务器环境的企业 JavaBeans 组件执行查询的结果通过网络发送到运行于 web 浏览器的客户端。 
<P>由于 <CODE>CachedRowSet</CODE> 对象是非连接的,所以和具有相同数据的 <CODE>ResultSet</CODE> 
对象相比更为简洁。因此,它特别适于向瘦客户端(如 PDA)发送数据,这种瘦客户端由于资源限制或安全考虑而不适于使用 JDBC 驱动程序。所以 
<CODE>CachedRowSet</CODE> 对象可提供一种“获取各行”的方式而无需实现全部 JDBC API。 
<P>
<H3>7.0 滚动和更新</H3><CODE>CachedRowSet</CODE> 对象的第二个主要用途是为那些本身不提供滚动和更新的 
<CODE>ResultSet</CODE> 对象提供这些功能。换句话说,当 DBMS 不提供对滚动和更新的完全支持时,可使用 
<CODE>CachedRowSet</CODE> 对象扩充启用 JDBC 技术的驱动程序(以下称为“JDBC 驱动程序”)的功能。要使不可滚动和只读的 
<CODE>ResultSet</CODE> 对象变得可滚动和可更新,程序员只需创建一个使用该 <CODE>ResultSet</CODE> 对象的数据所填充的 
<CODE>CachedRowSet</CODE> 对象即可。以下代码片断演示了这一过程,其中 <CODE>stmt</CODE> 是一个 
<CODE>Statement</CODE> 对象。 <PRE>    ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEES");
    CachedRowSetImpl crs = new CachedRowSetImpl();
    crs.populate(rs);
 </PRE>
<P>现在对象 <CODE>crs</CODE> 与对象 <CODE>rs</CODE> 一样,也包含了取自表 <CODE>EMPLOYEES</CODE> 
的数据。不同的是 <CODE>crs</CODE> 的指针可以向前、向后移动,或者移动到特定行,即使 <CODE>rs</CODE> 
的指针只能向前移动也是如此。此外,即使 <CODE>rs</CODE> 是不可更新的,<CODE>crs</CODE> 
也将是可更新的,因为在默认情况下,<CODE>CachedRowSet</CODE> 对象是可滚动和可更新的。 
<P>总之,可将 <CODE>CachedRowSet</CODE> 
对象简单地看成是一个非连接的行集合,这些行将缓存在数据源外部。由于它比较小并且是可序列化的,所以它可以轻松地通过导线发送,并且非常适合于向瘦客户端发送数据。但是 
<CODE>CachedRowSet</CODE> 对象也有局限性:它的大小限制在它一次可在内存中存储的数据量范围内。 
<P>
<H3>8.0 获得通用数据访问</H3><CODE>CachedRowSet</CODE> 
类的另一个优势在于它能够从关系数据库以外各种数据源检索并存储数据。可以实现 rowset 的 reader 
读取任何表格数据源(包括电子表格或平面文件)的数据,并用该数据填充其 rowset。因为 <CODE>CachedRowSet</CODE> 
对象及其元数据都可以从头创建,所以充当 rowset 工厂的组件可以使用此功能来创建一个包含非 SQL 数据源数据的 rowset。但是,大部分情况下,希望 
<CODE>CachedRowSet</CODE> 对象包含使用 JDBC API 从 SQL 数据库中获取的数据。 
<P>
<H3>9.0 设置属性</H3>所有 rowset 都维护一个属性集,通常使用某种工具来设置这些属性。rowset 具有的属性的数量和种类各不相同,这取决于 
rowset 的用途及其获得数据的方式。例如,从 <CODE>ResultSet</CODE> 对象获得其数据的 rowset 
需要设置那些建立数据库连接所需的属性。如果某个 rowset 使用 <CODE>DriverManager</CODE> 
设施建立连接,则它需要设置一个标识合适驱动程序的 JDBC URL 属性,还需要设置那些提供用户名和密码的属性。另一方面,如果 rowset 使用 
<CODE>DataSource</CODE> 对象建立连接(这是首选的方法),则它无需设置 JDBC URL 
属性。但是它需要设置用于数据源逻辑名、用户名和密码的属性。 
<P>注:要使用 <CODE>DataSource</CODE> 对象建立连接,该 <CODE>DataSource</CODE> 对象必须已经向使用 Java 
Naming and Directory Interface<SUP><FONT size=-2>TM</FONT></SUP> (JNDI) API 
的命名服务注册。通常由具有系统管理员资格的人员完成此注册。 
<P>为了能够使用数据库的数据填充,rowset 需要设置 command 属性。此属性是一种 <CODE>PreparedStatement</CODE> 
对象的查询,该对象允许查询具有在运行时(而不是设计时)设置的参数占位符。要用各种值设置这些占位符参数,rowset 要为设置每种数据类型的值提供设置方法,类似于 
<CODE>PreparedStatement</CODE> 接口提供的设置方法。 
<P>以下代码片断展示了如何设置 <CODE>CachedRowSet</CODE> 对象 <CODE>crs</CODE> 的 command 
属性。注意,如果使用某种工具设置属性,则这就是该工具应使用的代码。 <PRE>    crs.setCommand("SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS " +
                   "WHERE CREDIT_LIMIT &gt; ? AND REGION = ?");
 </PRE>
<P>用于设置该命令占位符参数的值被包含在 <CODE>RowSet</CODE> 对象的 <CODE>params</CODE> 字段中,该字段是一个 
<CODE>Vector</CODE> 对象。<CODE>CachedRowSet</CODE> 类为设置其 <CODE>params</CODE> 
字段中的元素提供了一组设置方法。以下代码片断演示了如何设置前一个示例查询中的两个参数。 <PRE>    crs.setInt(1, 5000);
    crs.setString(2, "West");
 </PRE>
<P><CODE>params</CODE> 
字段现在包含两个元素,每个元素都是一个两元素长的数组。第一个元素是参数号;第二个元素是要设置的值。在这种情况下,<CODE>params</CODE> 
的第一个元素是 <CODE>1</CODE>,<CODE>5000</CODE>,第二个元素是 
<CODE>2</CODE>,<CODE>"West"</CODE>。当应用程序调用方法 <CODE>execute</CODE> 时,它会依次调用此 
<CODE>RowSet</CODE> 对象的 reader,该 reader 会依次调用其 <CODE>readData</CODE> 
方法。作为实现的一部分,<CODE>readData</CODE> 将获得 <CODE>params</CODE> 
中的值并使用这些值设置命令的占位符参数。以下代码片断说明了在获得 <CODE>Connection</CODE> 对象 <CODE>con</CODE> 后 
reader 如何执行此操作。 <PRE>    PreparedStatement pstmt = con.prepareStatement(crs.getCommand());
    reader.decodeParams();
    // decodeParams figures out which setter methods to use and does something
    // like the following:
    //    for (i = 0; i &lt; params.length; i++) {
    //        pstmt.setObject(i + 1, params[i]);
    //    }
 </PRE>
<P>这里用于 <CODE>crs</CODE> 的命令是查询 <CODE>"SELECT FIRST_NAME, LAST_NAME, ADDRESS 
FROM CUSTOMERS WHERE CREDIT_LIMIT &gt; 5000 AND REGION = 
"West"</CODE>。<CODE>readData</CODE> 方法使用以下代码行执行此命令后,它会获得 <CODE>rs</CODE> 
的数据,该数据用于填充 <CODE>crs</CODE>。 <PRE>     ResultSet rs = pstmt.executeQuery();
 </PRE>
<P>上述代码片断说明了在后台进行的操作;这些操作不会出现在应用程序中,因为应用程序不会调用 <CODE>readData</CODE> 和 
<CODE>decodeParams</CODE> 之类的方法。相反,以下代码片断展示了应用程序可能执行的操作。它设置 rowset 的命令、设置 
command 属性并执行该命令。只需调用 <CODE>execute</CODE> 方法,就可使用从表 <CODE>CUSTOMERS</CODE> 
请求的数据生成 <CODE>crs</CODE>。 <PRE>    crs.setCommand("SELECT FIRST_NAME, LAST_NAME, ADDRESS FROM CUSTOMERS" +
                   "WHERE CREDIT_LIMIT &gt; ? AND REGION = ?");
    crs.setInt(1, 5000);
    crs.setString(2, "West");
    crs.execute();
 </PRE>
<H3>10.0 分页数据</H3>因为 <CODE>CachedRowSet</CODE> 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -