SlideShare a Scribd company logo
1 of 12
<<JDK6 jdbc api 和 jdbc4.0 规范 >>



描述从 jdk5 开始已经有部分数据库驱动支持以下特性:
                                                   java.sql.ResultSet
                                                  <<extends>>                       <<接口>>
                                                                        javax.sql.rowset.spi.SyncResolver


                                                    <<接口>>                    <<extends>>
                                                 javax.sql.RowSet
                                   <<extends>>                          <<extends>>          <<接口>>
            <<接口>>                                                                          JdbcRowSet
          CachedRowSet                                                  <<extends>>
                                   <<extends>>
             <<extends>>

                                                    <<接口>>
            <<接口>>                          javax.sql.rowset.Joinable
            WebRowSet



      <<extends>>    <<extends>>




   <<接口>>            <<接口>>
FilteredRowSet      JoinRowSet

                     类继承结构图



Joinable


RowSet


    RowSet 的 离 线 操作 能 够 有 效 的利 用 计 算 机 越来 越 充 足 的 内存 , 减 轻 数 据库 服 务 器
的负担,由于数据操作都是在内存中进行然后批量提交到数据源,灵活性和性能都有了
很 大 的 提 高 。 RowSet 默 认 是 一 个 可 滚 动 , 可 更 新 , 可 序 列 化 的 结 果 集 , 而 且 它 作 为
JavaBeans,可以方便地在网络间传输,用于两端的数据同步。
该接口添加了对 JavaBeansTM 组件模型的 JDBC API 支持。可用作可视化 Bean 开发环境
中的 JavaBeans 组件,它可以在设计时创建和配置并在运行时执行。
  RowSet 接口提供一组 JavaBeans 属性,这些属性允许配置一个 RowSet 实例来连接 JDBC
数据源并从中读取某些数据。    提供一组设置方法(setInt、setBytes、setString 等等)将输入参数传
递到 rowset 命令属性的方式。在一般情况下,此命令是 rowset 从关系数据库获取其数据时所使
用的 SQL 查询。
  RowSet 接口支持 JavaBeans 事件,允许应用程序中的其他组件在 rowset 发生事件时(如
值的更改)得到通知。
  任何人都可以提供 RowSet 接口的实现,包括希望将 RowSet 实现作为其 JDBC 产品的一
部分提供的 JDBC 驱动程序供应商。


  RowSet 对象可以建立一个与数据源的连接并在其整个生命周期中维持该连接,在此情况下,
该对象被称为连接的 rowset。rowset 还可以建立一个与数据源的连接,从而获取数据,然后关
闭它。这种 rowset 被称为非连接 rowset。


  非连接 rowset 可以在断开时更改其数据,然后将这些更改发送回原始数据源,不过它必
须重新建立连接才能完成此操作。



JdbcRowSet


    ResultSet 对象的包装器使得将该结果集用作 JavaBeansTM 组件成为可能。
JdbcRowSet 是一个连接的 rowset,也就是说,它使用启用 JDBC 技术的驱动程序来维持它与
数据库的连接,所以它也能有效地使驱动程序成为 JavaBeans 组件。
  因为它始终连接到其数据库,所以 JdbcRowSet 的实例可以简单地采用在其上进行调用的
方法,并依次对其 ResultSet 对象调用这些方法。因此,结果集可以是(举例来说)Swing 应用
程序中的一个组件。
  JdbcRowSet 对象的另一个优点是可使用它让 ResultSet 对象可滚动和可更新 。默
认情况下,所有 RowSet 对象都是可滚动的和可更新的。如果使用的驱动程序和数据库不支持结
果集的滚动和 /或更新,则应用程序可以组装一个带 ResultSet 对象数据的 JdbcRowSet 对象,
然后在该 JdbcRowSet 对象上操作,就好像它是 ResultSet 对象一样。
  JdbcRowSet 接口的参考实现 JdbcRowSetImpl 提供了默认构造方法的实现。使用默
认值初始化新的实例,可根据需要使用新值设置这些默认值。在调用新实例的 execute 方法之
前,它实际上无法真正发挥作用。通常,此方法执行以下操作:


  •   建立与数据库的连接
  •   创建一个 PreparedStatement 对象并设置其所有占位符参数
  •   执行语句来创建 ResultSet 对象


  以下代码片断创建了一个 JdbcRowSetImpl 对象、设置命令连接属性、设置占位符参数,然
后调用方法 execute。
   JdbcRowSetImpl jrs = new JdbcRowSetImpl();
  jrs.setCommand("SELECT * FROM TITLES WHERE TYPE = ?");
jrs.setURL("jdbc:myDriver:myAttribute");
  jrs.setUsername("cervantes");
  jrs.setPassword("sancho");
  jrs.setString(1, "BIOGRAPHY");
  jrs.execute();




SyncResolver,


   当发生同步冲突时,它允许应用程序使用手工决策树来确定应该执行的操作。虽然应
用程序手工解决同步冲突并不是委托过程,但 此框架 还是提 供了一 些发生 冲突时 委托应 用
程序的方法。
  冲突是指RowSet 对象的原始行值与数据源中的值不 匹配的情况,它 指示自最后一
次同步以来数据源行已被修改。   还要注意,RowSet 对象的原始值就是最后一次同步之前
的值,不必是其初始值。
   SyncResolver 的 参 考 实 现 实 现 了 CachedRowSet 接 口 , 但 是 其 他 实 现 可 以 选 择 实 现
JdbcRowSet 接口,以满足特定的需要。
  这一新的 SyncResolver 对象具有与 正在尝试 同步的 RowSet 对象相同的行数和列数 。
SyncResolver 对象包含数据源中导致冲突的值,其他值都为 null。另外,它包含关于每
个冲突的信息。
  SyncResolver 对象(如 resolver)跟踪存在冲突的每个行中的冲突。它还可以锁定受
rowset 命令影响的表,以便在解决当前冲突时不再发生其他冲突。
   可以从 SyncResolver 对象获取以下几种信息:
    发生冲突时正试图进行的操作:
       SyncProvider 接口定义了四个常量来描述可能发生的状态。
       //RowSet 对象正试图执行的操作类型
       int operation = resolver.getStatus();
       第四个常量指示不存在冲突。
      数据源中导致冲突的值


当 RowSet 对象更改并尝试写入到数据源的值自上一次同步以来也在数据源中被更改时,
会发生冲突。应用程序可以调用 SyncResolver 的方法 getConflictValue 来获取数据源中导
致冲突的值,因为 SyncResolver 对象中的值是取自数据源的冲突值。
    java.lang.Object conflictValue = resolver.getConflictValue(2);


注意,resolver 中的列可以使用列号指定(如以上代码行中所示),也可以用列名称指定。


使用方法 getStatus 和 getConflictValue 获取到的信息,应用程序可以做出应在数据源中保
留哪一个值的决定。然后,应用程序调用 SyncResolver 对象的方法
setResolvedValue,它可以设置 RowSet 对象中和数据源中要保留的值。


    resolver.setResolvedValue("DEPT", 8390426);
在以上代码行中,列名称指定 RowSet 对象中要使用给定值设置的列。也可以用列号来指定列。


解决当前冲突行中的所有冲突之后,应用程序会调用方法 setResolvedValue,并对
SyncResolver 对象中每个冲突行重复此过程。


    要使导航 SyncResolver 对象更容易,尤其是存在大量没有冲突的行时,SyncResolver 接
口定义了方法 nextConflict 和 previousConflict,它们只移动到至少包含一个冲突值的行。
然后,应用程序通过提供列号作为参数调用 SyncResolver 的方法 getConflictValue,以获取
冲突值本身。




CachedRowSet


    CachedRowSet 对象 是 一 个 数 据行 的 容 器 , 可在 内 存 中 缓 存其 各 行 , 这 使得 进 行 操
作时无需总是连接到数据源。
  此外,它还是一个 JavaBeansTM 组件,是可滚动、可更新、可序列化的。
   CachedRowSet 对象通常包含结果集中的行,但它也 可 以 包 含 任 何 具 有 表 格 式 的 文 件
(如电子表格)中的行 。参考实现只支持从 ResultSet 对象中获取数据,但是开发人员可以
扩展 SyncProvider 实现,以提供对其他表格数据源的访问。


    CachedRowSet 对象是一个 非连接 rowset,这意味着它只会短暂地连接其数据源。连
接数据源发生在读取数据以用各行填充自身,以及将更改传播回其底层数据源时。其余时间
CachedRowSet 对象是非连接的,包括修改它的数据时。非连接使 RowSet 对象更为简洁,
因此更容易传递给另一个组件。例如,非连接 RowSet 对象可以被序列化并通过导线传
递到瘦客户端 (thin client),如个人数字助理(personal digital assistant,PDA)。


使用参考实现 (RI) 中提供的默认 CachedRowSet 构造方法来创建默认的 CachedRowSet 对象。
可以实现 writer 以在检查和避免冲突方面实施不同程度的关注。(
     CachedRowSetImpl crs = new CachedRowSetImpl();
    SyncProvider 对象提供了带有 reader 的(RowSetReader 对象)的
CachedRowSet 对象,用于从数据源读取数据以便用该数据填充自身。可以实现 reader 从
ResultSet 对象或者表格式的文件中读取数据。SyncProvider 对象还提供了
writer(RowSetWriter 对象),用于同步在与底层数据源中的数据断开连接时对 CachedRowSet
对象数据所做的任何更改。


应用程序可以找到已注册的 SyncProvider 实现。


java.util.Enumeration providers = SyncFactory.getRegisteredProviders();
CachedRowSet 对象可使用两种方式来指定它将使用的 SyncProvider 对象。


         向构造方法提供实现名
         以下代码行创建 CachedRowSet 对象 crs2,使用默认值初始化该对象,但其
         SyncProvider 对象是指定的。
         CachedRowSetImpl crs2 = new CachedRowSetImpl(
                                       "com.fred.providers.HighAvailabilityProvider");


        使用 CachedRowSet 方法 setSyncProvider 设置 SyncProvider
         以下代码行为 crs 重置 SyncProvider 对象,该 CachedRowSet 对象是使用默认构
         造方法创建的。
            crs.setSyncProvider("com.fred.providers.HighAvailabilityProvider");




 获取     RowSetMetaData
  通过在 RowSetMetaData 对象上调用 ResultSetMetaData 和 RowSetMetaData 的方法,应用
程序可以获得有关 CachedRowSet 对象中各列的信息。
 RowSetMetaData rsmd = (RowSetMetaData)crs.getMetaData();
  int count = rsmd.getColumnCount();
  int type = rsmd.getColumnType(2);
RowSetMetaData 接口与 ResultSetMetaData 接口有两方面不同。


   •    它包括设置方法:当使用取自不同 ResultSet 对象的数据填充 RowSet 对象时,该
        RowSet 对象在内部使用这些方法。
   •    它包含较少的获取方法:某些 ResultSetMetaData 方法无法应用到 RowSet 对象。例如,
        不会应用那些获取某个列值是可写入的还是只读的方法,因为 RowSet 对象的所有列要
        么是可写入的,要么是只读的,这取决于该 rowset 是否可更新。


    注 : 要 返 回 RowSetMetaData 对 象 , 实 现 必 须 重 写 java.sql.ResultSet 中 定 义 的
getMetaData() 方法返回 RowSetMetaData 对象。


   更新 CachedRowSet 对象
         更新 CachedRowSet 对象与更新 ResultSet 对象类似,但是因为更新 rowset 时它并未
    连接到其数据源,所以必须执行额外的步骤才能使更改在底层数据源中生效。调用方法
    updateRow 或 insertRow 后,CachedRowSet 对象还必须调用方法 acceptChanges 使更新写
    入数据源。以下示例(其中指针在 CachedRowSet 对象 crs 中的行上)显示了更新当前行中
    两个列值并同样更新 RowSet 对象的底层数据源所需的代码。
  crs.updateShort(3, 58);
  crs.updateInt(4, 150000);
  crs.updateRow();
  crs.acceptChanges();


   下一个示例演示了移至插入行、在插入行上构建新行、将新行插入 rowset,然后调用方法
acceptChanges 将新行添加到底层数据源。注意,与获取方法一样,更新方法可以采用列索
  引或列名来指定所操作的列。
   crs.moveToInsertRow();
   crs.updateString("Name", "Shakespeare");
   crs.updateInt("ID", 10098347);
   crs.updateShort("Age", 58);
   crs.updateInt("Sal", 150000);
   crs.insertRow();
   crs.moveToCurrentRow();
   crs.acceptChanges();


注:insertRow() 方法在何处插入 CachedRowSet 对象的插入行内容是由实现定义的 。
CachedRowSet 接口的参考实现紧随当前行插入新行,但也可以实现为在任何其他位置插入新行。



有关这些示例的另一个注意点是它们使用方法 acceptChanges 的方式。通过内部调用 RowSet
对象的 writer 将这些更改写入数据源,从而将 CachedRowSet 对象中的更改传播回底层数据
源的正是此方法。为此,writer 不得不承受建立到数据源的连接所带来的开销。上述两个代码片
断在调用 updateRow 或 insertRow 后立即调用方法 acceptChanges。但是,如果更改了多个
行,则更高效的做法是在调用所有 updateRow 和 insertRow 后再调用
acceptChanges。如果只调用 acceptChanges 一次,则只需要建立一个连接。


  更新底层数据源
   执行 acceptChanges 方法时,在后台调用 CachedRowSet 对象的 writer(一个
RowSetWriterImpl 对象),以便将对 rowset 所作的更改写入底层数据源。实现该 writer 以
建立到数据源的连接并写入更新。


  可通过 SyncProvider 接口的实现提供 writer,这已第 1 部分“创建
CachedRowSet 对象”中讨论。默认的参考实现提供者 RIOptimisticProvider 会实现其
writer 使用乐观并发控制 (optimistic concurrency control) 机制。也就是说,在
rowset 与数据库断开时它不对底层数据库维持任何锁定,在将数据写入数据源之前它只是检查
是否有冲突。如果存在冲突,则不向数据源写入任何内容。


  SyncProvider 类提供的 reader/writer 方法是可插入的,允许自定义数据的获取和更新。
如果需要其他的并发控制机制,可使用方法 setSyncProvider 插入其他 SyncProvider 实现。


  要使用乐观并发控制例程,RIOptismisticProvider 要同时维护其当前值及其原始值(刚
好位于当前值之前的值)。注意,如果没有对 RowSet 对象中的数据进行任何更改,则其当前值
和原始值相同,都是最初填充 RowSet 对象时使用的值。但是,一旦更改了 RowSet 对象中的任
何值,当前值和原始值就不同了,尽管此时原始值仍是最初的值。随着后续对 RowSet 对象中的
数据进行更改,其原始值和当前值仍保持不同,但是其原始值将是前一个当前值。
关注原始值允许 writer 对 RowSet 对象的原始值和数据库中的值进行比较。如果
数据库中的值与 RowSet 对象的原始值不同,则意味着数据库中的值已经更改,出现了
冲突。writer 是否检查冲突、检查的程度如何,以及它如何处理冲突都取决于它的实现方式。


   注册和通知侦听器

   作为 JavaBeans 组件,参与 JavaBeans 事件模型的所有 rowset 都继承了用来注册侦听
器和用来通知这些侦听器 BaseRowSet 类中发生更改的各种方法。CachedRowSet 对象的侦听器
是一个组件,只要 rowset 中发生更改,它就应得到通知。例如,如果 CachedRowSet 对象包含
查询的结果,并且这些结果将以表格和条形图之类的形式显示,则可以向 rowset 将该表格和
条形图注册为侦听器,这样它们可以更新以反映各种更改。要成为侦听器,表格和条形图类
必须实现 RowSetListener 接口。然后可将它们添加到 CachedRowSet 对象的侦听器
列表,如以下代码行所示。


   crs.addRowSetListener(table);
   crs.addRowSetListener(barGraph);



   每个移动指针或更改数据的 CachedRowSet 方法也将更改通知已注册的侦听器,所以当
crs 中发生更改时 table 和 barGraph 将得到通知。


   向瘦客户端传递数据

   使用 CachedRowSet 对象的主要原因之一是要在应用程序的不同组件之间传递数据。因为
CachedRowSet 对象是可序列化的,所以可使用它(举例来说)将运行于服务器环境的企业
JavaBeans 组件执行查询的结果通过网络发送到运行于 web 浏览器的客户端。


   由于 CachedRowSet 对象是非连接的,所以和具有相同数据的 ResultSet 对象相比更为简
洁。因此,它特别适于向瘦客户端(如 PDA)发送数据,这种瘦客户端由于资源限制或安全考虑
而不适于使用 JDBC 驱动程序。所以 CachedRowSet 对象可提供一种“获取各行”的方式而无需
实现全部 JDBC API。


    滚动和更新

   CachedRowSet 对象的第二个主要用途是为那些本身不提供滚动和更新的
ResultSet 对象提供这些功能。换句话说,当 DBMS 不提供对滚动和更新的完全支持时,可
使用 CachedRowSet 对象扩充启用 JDBC 技术的驱动程序(以下称为“JDBC 驱动程序”)的功
能。要使不可滚动和只读的 ResultSet 对象变得可滚动和可更新,程序员只需创建一个使用该
ResultSet 对象的数据所填充的 CachedRowSet 对象即可。以下代码片断演示了这一过程,其中
stmt 是一个 Statement 对象。
   ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEES");
   CachedRowSetImpl crs = new CachedRowSetImpl();
   crs.populate(rs);
现在对象 crs 与对象 rs 一样,也包含了取自表 EMPLOYEES 的数据。不同的是 crs 的指
针可以向前、向后移动,或者移动到特定行,即使 rs 的指针只能向前移动也是如此。此外,即
使 rs 是不可更新的,crs 也将是可更新的,因为在默认情况下,CachedRowSet 对象是可滚动
和可更新的。


总之,可将 CachedRowSet 对象简单地看成是一个非连接的行集合,这些行将缓存在数据源外
部。由于它比较小并且是可序列化的,所以它可以轻松地通过导线发送,并且非常适合于向瘦客
户端发送数据。但是 CachedRowSet 对象也有局限性:它的大小限制在它一次可在内存
中存储的数据量范围内。


 获得通用数据访问

  CachedRowSet 类的 另 一 个 优 势在 于 它 能 够 从关 系 数 据 库 以外 各 种 数 据 源获 取 并 存
储数据。可以实现 rowset 的 reader 读取任何表格数据源(包括电子表格或平面文件)的数据,
并用该数据填充其 rowset。因为 CachedRowSet 对象及其元数据都可以从头创建,所以充
当 rowset 工厂的组件可以使用此功能来创建一个包含非 SQL 数据源数据的 rowset。但是
大部分情况下,希望 CachedRowSet 对象包含使用 JDBC API 从 SQL 数据库中获取的数据。


设置属性
  如果某个 rowset 使用 DriverManager 设施建立连接,则它需要设置一个标识合适驱动
程序的 JDBC URL 属性,还需要设置那些提供用户名和密码的属性。另一方面,如果 rowset
使用   DataSource 对象 建 立 连 接 (这 是 首 选 的 方法 ) , 则 它 无需 设 置 JDBC URL 属
性。但是它需要设置用于数据源逻辑名、用户名和密码的属性。
分页数据
因为 CachedRowSet 对象在内存中存储数据,所以它在任一时间可以包含的数据量是由可用的
内存量决定的。要避开此限制,CachedRowSet 对 象 可 以 数 据 块 ( 称 为 页 ) 的 形 式 从
ResultSet 对象中获取数据。要利用此机制,应用程序应使用方法 setPageSize 设置一
页中要包括的行数。    换句话说,如果页大小设置为 5,则一次从数据源中获取一个 5 行的数据
块。应用程序也可选择设置一次可获取的最大行数。如果最大行数设置为 0,或者未设置最大行
数,则对一次获取的行数没有限制。


设置各个属性后,必须使用方法 populate 或方法 execute 用数据填充
CachedRowSet 对象。以下代码行演示了如何使用方法 populate。注意,该方法的这种形式采
用两个参数,ResultSet 句柄和 ResultSet 对象中的行,从该行开始获取各行。


     CachedRowSet crs = new CachedRowSetImpl();
     crs.setMaxRows(20);
     crs.setPageSize(4);
     crs.populate(rsHandle, 10);


运行此代码时,将使用 rsHandle 中从第 10 行开始的 4 行数据填充 crs。
下一个代码片断展示了如何使用方法 execute 填充 CachedRowSet 对象,该方法可以采用
Connection 对象作为一个参数,也可以不采用。此代码向 execute 传递 Connection 对象
conHandle。


注意,以下代码片断和上述代码片断有两处差别。首先,没有调用方法 setMaxRows,所以没有
对 crs 可以包含的行数设置限制。(记住,对于 crs 在内存中可以存储的数据量,总是有一个
最高限制。)第二个差别是不能向方法 execute 传递 ResultSet 对象中起始获取行的行号。此
方法始终从第一行开始获取。


    CachedRowSet crs = new CachedRowSetImpl();
    crs.setPageSize(5);
    crs.execute(conHandle);


运行此代码后,crs 将包含由 crs 的命令所生成的 ResultSet 对象中的 5 行数据。crs 的 writer
将使用 conHandle 连接数据源并执行 crs 的命令。然后应用程序就能够在 crs 中的数据上进行
操作,方式与在任何其他 CachedRowSet 对象的数据上进行操作的方式相同。


要访问下一页(数据块),应用程序可调用方法 nextPage。此方法创建新的
CachedRowSet 对象并用下一页的数据填充。例如,假定 CachedRowSet 对象的命令返回一个具
有 1000 行数据的 ResultSet 对象 rs。如果页大小设置为 100,则首次调用方法 nextPage 将
创建一个包含 rs 前 100 行的 CachedRowSet 对象。在使用这前 100 行的数据执行完所需的操
作后,应用程序可以再次调用方法 nextPage 创建另一个带有 rs 第二个 100 行数据的
CachedRowSet 对象。第一个 CachedRowSet 对象中的数据不再存在于内存中,因为它已被第二
个 CachedRowSet 对象的数据替换了。调用方法 nextPage 10 次后,第十个 CachedRowSet 对
象将包含 rs 最后 100 行存储在内存中的数据。在任意给定时间,内存中仅存储一个
CachedRowSet 对象的数据。


只要当前页不是各行的最后一页,方法 nextPage 就返回 true,没有其他页时,则返回
false。因此,可在 while 循环中使用它来获取所有页,正如在以下代码行中所演示的。


    CachedRowSet crs = CachedRowSetImpl();
    crs.setPageSize(100);
    crs.execute(conHandle);


    while(crs.nextPage()) {
        while(crs.next()) {
             . . . // operate on chunks (of 100 rows each) in crs,
                   // row by row
        }
    }


运行此代码片断后,应用程序会遍历所有 1000 行,但是每次内存中的数据只有 100 行。
CachedRowSet 接口还定义了方法 previousPage。正如方法 nextPage 类似于 ResultSet 方法
next,方法 previousPage 也类似于 ResultSet 方法 previous。与方法 nextPage 类似,
previousPage 创建一个 CachedRowSet 对象,包含作为页大小设置的行数。因此,(举例来说)
方法 previousPage 可用在上述代码片断末尾的 while 循环中,以从最后一页开始逆向遍历到
第一页。方法 previousPage 也与 nextPage 类似,因为它也可以用在 while 循环中,不同之
处在于它是在前面还有页时返回 true,前面没有页时返回 false。


通过将指针定位于每页最后一行的后面(如以下代码片断所执行的),方法 previous 就可以
在每页中从最后一行遍历到第一行。代码也可将指针置于每页第一行的前面,然后在 while 循
环中使用 next 方法,以在每页中从最第一行遍历到最后一行。


以下代码片断假定是前一个代码片断的继续,这意味着第十个 CachedRowSet 对象的指针位于
最后一行。代码将指针移到最后一行的后面,这样第一次调用方法 previous 会将指针
放回到最后一行上。遍历最后一页(CachedRowSet 对象 crs )的所有行后,代码接着
会进入 while 循环以获得第九页、向后遍历各行、转至第八页、向后遍历各行,依此类推,
直到第一页的第一行为止。


    crs.afterLast();
    while(crs.previous())   {
        . . . // navigate through the rows, last to first
    {
    while(crs.previousPage())   {
        crs.afterLast();
        while(crs.previous())   {
            . . . // go from the last row to the first row of each page
        }
    }




WebRowSet


标准的 WebRowSet XML 模式定义位于以下 URI 中:


        http://java.sun.com/xml/ns/jdbc/webrowset.xsd


所有 WebRowSet 接口的标准实现必须使用该文档格式以确保互操作性。此外,WebRowSet 模式
使用特定的 SQL/XML 模式注释,从而确保较高的跨平台互操作性。目前 ISO 组织正在为此而努
力。SQL/XML 定义可从以下 URI 中得到:
        http://standards.iso.org/iso/9075/2002/12/sqlxml


模式定义从以下三个不同方面描述 RowSet 对象的内部数据:
•   属性 除了较为通用的 RowSet 属性之外,这些属性还描述标准同步提供者属性。
  •   元数据 此项描述与 WebRowSet 对象管理的表格结构关联的元数据。描述的元数据与在
      底层 java.sql.ResultSet 接口中可访问的元数据是紧密联系在一起的。
  •   数据 此项描述原始数据(自从 WebRowSet 对象的上一次填充或上一次同步以来的数
      据状态)和当前数据。通过跟踪原始数据和当前数据之间的 delta,WebRowSet 维持其
      数据中的更改与原始数据源同步的能力。



FilteredRowSet


  有时 RowSet 对象需要对其内容进行某种程度的过滤。一种可能的解决方案是为所有标准的
RowSet 实现提供一种查询语言;但是这对诸如非连接 RowSet 对象 之类的轻量级组件而言是
一种不切实际的方法。FilteredRowSet 接口寻求在不提供重量级查询语言和这种查询语言所需
处理的情况下解决这一需求问题。




JoinRowSet


    JoinRowSet 接口提供了一种机制,用于将取自不同 RowSet 对象的相关数据组合到一个
JoinRowSet 对象中,该对象表示一个 SQL JOIN。换句话说,JoinRowSet 对象可作为一个数据容
器,这些数据取自那些形成 SQL JOIN 关系的 RowSet 对象。


   Joinable 接口提供了一些用于设置、获取和取消设置匹配列的方法 , 匹 配 列 建 立 SQL
JOIN 关系的基础。通过将匹配列提供给恰当形式的 JointRowSet 方法 addRowSet 也可设
置匹配列。
  无连 接的 RowSet 对象 ( CachedRowSet 对象和 扩展 CachedRowSet 接口的 实现)
没有一种能在 RowSet 之间建立 SQL JOIN 且无需 重新连接数据源(该操作开 销很大)
的标准方式。JoinRowSet 接口是专门为解决这一需求而设计的。



任何   RowSet 对象都可添加到 JoinRowSet 对象,以成为 SQL JOIN 关系的一部分。
可将任意数目的 RowSet 对象添加到 JoinRowSet 的实例中,前提是只要这些对象可以在
SQL JOIN 中关联起来。
Joinable 接口提供了用于建立公共属性的方法,可通过设置匹配列 来建立。匹配列通常与主
键相符,但是不要求匹配列与主键相同。通过建立然后强制执行匹配列, JoinRowSet 对象可
在 RowSet 对象之间建立 JOIN 关系,无需可用关系型数据库的协助。



可设置以下 SQL JOIN 类型:


  •   CROSS_JOIN
•    FULL_JOIN
  •    INNER_JOIN - 未设置 JOIN 类型时使用的默认值
  •    LEFT_OUTER_JOIN
  •    RIGHT_OUTER_JOIN


注意,如果未设置类型,则 JOIN 将自动为 INNER_JOIN。JoinRowSet 接口中各字段的注释说明
了这些 JOIN 类型,它们都是标准的 SQL JOIN 类型。



可用两种方式来设置匹配列:


  •    通过调用 Joinable 的方法 setMatchColumn
       将 RowSet 对象添加到 JoinRowSet 对象之前,这是可以设置匹配列的唯一方法。为了
       使用方法 setMatchColumn,RowSet 对象必须已经实现了 Joinable 接口。一旦设置了
       匹配列值,则可在任意时间使用此方法来重置匹配列。
  •    通过调用某种形式的 JoinRowSet 方法 addRowSet(使用列名或列号,或者列名数组
       或列号数组)
       5 个 addRowSet 方法中有 4 个采用匹配列作为参数。这 4 个方法可在将 RowSet 对
       象添加到 JoinRowSet 对象时设置或重置匹配列。


以上具体示例请参见 jdk1.6 API javax.sql.包




JDBC

More Related Content

What's hot

J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识yiditushe
 
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理maclean liu
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制maclean liu
 
A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题WASecurity
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文Guo Albert
 
了解Oracle在线重定义online redefinition
了解Oracle在线重定义online redefinition了解Oracle在线重定义online redefinition
了解Oracle在线重定义online redefinitionmaclean liu
 
107个常用javascript语句 oss 计算技术 - ossez info of tech
107个常用javascript语句   oss 计算技术 - ossez info of tech107个常用javascript语句   oss 计算技术 - ossez info of tech
107个常用javascript语句 oss 计算技术 - ossez info of techYUCHENG HU
 
4 hibernate对象管理和缓存结构
4 hibernate对象管理和缓存结构4 hibernate对象管理和缓存结构
4 hibernate对象管理和缓存结构Zelin Wang
 
Jsp面试知识
Jsp面试知识Jsp面试知识
Jsp面试知识yiditushe
 
Jdbc中驱动加载的过程分析(下)
Jdbc中驱动加载的过程分析(下)Jdbc中驱动加载的过程分析(下)
Jdbc中驱动加载的过程分析(下)yiditushe
 
Hibernate查询
Hibernate查询Hibernate查询
Hibernate查询llying
 
线程编程方面
线程编程方面线程编程方面
线程编程方面yiditushe
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践guestf5121c
 
Hibernate 映射配置文件详解
Hibernate 映射配置文件详解Hibernate 映射配置文件详解
Hibernate 映射配置文件详解wpscbbn405
 
Java SE 7 技術手冊 - 課後練習解答
Java SE 7 技術手冊 - 課後練習解答Java SE 7 技術手冊 - 課後練習解答
Java SE 7 技術手冊 - 課後練習解答Justin Lin
 
Lucene2 4学习笔记1
Lucene2 4学习笔记1Lucene2 4学习笔记1
Lucene2 4学习笔记1yiditushe
 
实时任务调度
实时任务调度实时任务调度
实时任务调度Tony Deng
 
Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1Zianed Hou
 

What's hot (20)

J2ee面试知识
J2ee面试知识J2ee面试知识
J2ee面试知识
 
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理【Maclean liu技术分享】深入理解oracle中mutex的内部原理
【Maclean liu技术分享】深入理解oracle中mutex的内部原理
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制
 
A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题
 
Spring 2.x 中文
Spring 2.x 中文Spring 2.x 中文
Spring 2.x 中文
 
了解Oracle在线重定义online redefinition
了解Oracle在线重定义online redefinition了解Oracle在线重定义online redefinition
了解Oracle在线重定义online redefinition
 
107个常用javascript语句 oss 计算技术 - ossez info of tech
107个常用javascript语句   oss 计算技术 - ossez info of tech107个常用javascript语句   oss 计算技术 - ossez info of tech
107个常用javascript语句 oss 计算技术 - ossez info of tech
 
4 hibernate对象管理和缓存结构
4 hibernate对象管理和缓存结构4 hibernate对象管理和缓存结构
4 hibernate对象管理和缓存结构
 
Jsp面试知识
Jsp面试知识Jsp面试知识
Jsp面试知识
 
组合、备忘录、建造者模式、原型
组合、备忘录、建造者模式、原型组合、备忘录、建造者模式、原型
组合、备忘录、建造者模式、原型
 
Jdbc中驱动加载的过程分析(下)
Jdbc中驱动加载的过程分析(下)Jdbc中驱动加载的过程分析(下)
Jdbc中驱动加载的过程分析(下)
 
Hibernate查询
Hibernate查询Hibernate查询
Hibernate查询
 
线程编程方面
线程编程方面线程编程方面
线程编程方面
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践
 
Sun java
Sun javaSun java
Sun java
 
Hibernate 映射配置文件详解
Hibernate 映射配置文件详解Hibernate 映射配置文件详解
Hibernate 映射配置文件详解
 
Java SE 7 技術手冊 - 課後練習解答
Java SE 7 技術手冊 - 課後練習解答Java SE 7 技術手冊 - 課後練習解答
Java SE 7 技術手冊 - 課後練習解答
 
Lucene2 4学习笔记1
Lucene2 4学习笔记1Lucene2 4学习笔记1
Lucene2 4学习笔记1
 
实时任务调度
实时任务调度实时任务调度
实时任务调度
 
Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1
 

Similar to Jdbc4 0 规范技术预研

Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作zhubin885
 
深入淺出 Web 容器 - Tomcat 原始碼分析
深入淺出 Web 容器  - Tomcat 原始碼分析深入淺出 Web 容器  - Tomcat 原始碼分析
深入淺出 Web 容器 - Tomcat 原始碼分析Justin Lin
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Servicesjavatwo2011
 
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫Justin Lin
 
整合資料庫
整合資料庫整合資料庫
整合資料庫Justin Lin
 
Huangjing renren
Huangjing renrenHuangjing renren
Huangjing renrend0nn9n
 
jsp基础速成精华讲解
jsp基础速成精华讲解jsp基础速成精华讲解
jsp基础速成精华讲解wensheng wei
 
香港六合彩
香港六合彩香港六合彩
香港六合彩aaveow
 
山頂洞人日記 - 回歸到最純樸的開發
山頂洞人日記 -  回歸到最純樸的開發山頂洞人日記 -  回歸到最純樸的開發
山頂洞人日記 - 回歸到最純樸的開發koji lin
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 zhen chen
 
运维系统开发与Rails 3页面开发实践
运维系统开发与Rails 3页面开发实践运维系统开发与Rails 3页面开发实践
运维系统开发与Rails 3页面开发实践Li JianYe
 
Mongo db技术分享
Mongo db技术分享Mongo db技术分享
Mongo db技术分享晓锋 陈
 
My sql管理基础 李春_v2
My sql管理基础 李春_v2My sql管理基础 李春_v2
My sql管理基础 李春_v2Pickup Li
 
Java并发核心编程
Java并发核心编程Java并发核心编程
Java并发核心编程wavefly
 
Terracotta And Continuent Based Clustering Architecture
Terracotta And Continuent Based Clustering ArchitectureTerracotta And Continuent Based Clustering Architecture
Terracotta And Continuent Based Clustering ArchitectureTarget Source
 
Java SE 8 技術手冊第 16 章 - 整合資料庫
Java SE 8 技術手冊第 16 章 - 整合資料庫Java SE 8 技術手冊第 16 章 - 整合資料庫
Java SE 8 技術手冊第 16 章 - 整合資料庫Justin Lin
 

Similar to Jdbc4 0 规范技术预研 (20)

Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作
 
深入淺出 Web 容器 - Tomcat 原始碼分析
深入淺出 Web 容器  - Tomcat 原始碼分析深入淺出 Web 容器  - Tomcat 原始碼分析
深入淺出 Web 容器 - Tomcat 原始碼分析
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
Servlet & JSP 教學手冊第二版 - 第 9 章:整合資料庫
 
整合資料庫
整合資料庫整合資料庫
整合資料庫
 
Huangjing renren
Huangjing renrenHuangjing renren
Huangjing renren
 
jsp基础速成精华讲解
jsp基础速成精华讲解jsp基础速成精华讲解
jsp基础速成精华讲解
 
香港六合彩
香港六合彩香港六合彩
香港六合彩
 
ev2oik
ev2oikev2oik
ev2oik
 
香港六合彩
香港六合彩香港六合彩
香港六合彩
 
Jsp
JspJsp
Jsp
 
Exodus2 大局观
Exodus2 大局观Exodus2 大局观
Exodus2 大局观
 
山頂洞人日記 - 回歸到最純樸的開發
山頂洞人日記 -  回歸到最純樸的開發山頂洞人日記 -  回歸到最純樸的開發
山頂洞人日記 - 回歸到最純樸的開發
 
Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储 Ria的强力后盾:rest+海量存储
Ria的强力后盾:rest+海量存储
 
运维系统开发与Rails 3页面开发实践
运维系统开发与Rails 3页面开发实践运维系统开发与Rails 3页面开发实践
运维系统开发与Rails 3页面开发实践
 
Mongo db技术分享
Mongo db技术分享Mongo db技术分享
Mongo db技术分享
 
My sql管理基础 李春_v2
My sql管理基础 李春_v2My sql管理基础 李春_v2
My sql管理基础 李春_v2
 
Java并发核心编程
Java并发核心编程Java并发核心编程
Java并发核心编程
 
Terracotta And Continuent Based Clustering Architecture
Terracotta And Continuent Based Clustering ArchitectureTerracotta And Continuent Based Clustering Architecture
Terracotta And Continuent Based Clustering Architecture
 
Java SE 8 技術手冊第 16 章 - 整合資料庫
Java SE 8 技術手冊第 16 章 - 整合資料庫Java SE 8 技術手冊第 16 章 - 整合資料庫
Java SE 8 技術手冊第 16 章 - 整合資料庫
 

Jdbc4 0 规范技术预研

  • 1. <<JDK6 jdbc api 和 jdbc4.0 规范 >> 描述从 jdk5 开始已经有部分数据库驱动支持以下特性: java.sql.ResultSet <<extends>> <<接口>> javax.sql.rowset.spi.SyncResolver <<接口>> <<extends>> javax.sql.RowSet <<extends>> <<extends>> <<接口>> <<接口>> JdbcRowSet CachedRowSet <<extends>> <<extends>> <<extends>> <<接口>> <<接口>> javax.sql.rowset.Joinable WebRowSet <<extends>> <<extends>> <<接口>> <<接口>> FilteredRowSet JoinRowSet 类继承结构图 Joinable RowSet RowSet 的 离 线 操作 能 够 有 效 的利 用 计 算 机 越来 越 充 足 的 内存 , 减 轻 数 据库 服 务 器 的负担,由于数据操作都是在内存中进行然后批量提交到数据源,灵活性和性能都有了 很 大 的 提 高 。 RowSet 默 认 是 一 个 可 滚 动 , 可 更 新 , 可 序 列 化 的 结 果 集 , 而 且 它 作 为 JavaBeans,可以方便地在网络间传输,用于两端的数据同步。
  • 2. 该接口添加了对 JavaBeansTM 组件模型的 JDBC API 支持。可用作可视化 Bean 开发环境 中的 JavaBeans 组件,它可以在设计时创建和配置并在运行时执行。 RowSet 接口提供一组 JavaBeans 属性,这些属性允许配置一个 RowSet 实例来连接 JDBC 数据源并从中读取某些数据。 提供一组设置方法(setInt、setBytes、setString 等等)将输入参数传 递到 rowset 命令属性的方式。在一般情况下,此命令是 rowset 从关系数据库获取其数据时所使 用的 SQL 查询。 RowSet 接口支持 JavaBeans 事件,允许应用程序中的其他组件在 rowset 发生事件时(如 值的更改)得到通知。 任何人都可以提供 RowSet 接口的实现,包括希望将 RowSet 实现作为其 JDBC 产品的一 部分提供的 JDBC 驱动程序供应商。 RowSet 对象可以建立一个与数据源的连接并在其整个生命周期中维持该连接,在此情况下, 该对象被称为连接的 rowset。rowset 还可以建立一个与数据源的连接,从而获取数据,然后关 闭它。这种 rowset 被称为非连接 rowset。 非连接 rowset 可以在断开时更改其数据,然后将这些更改发送回原始数据源,不过它必 须重新建立连接才能完成此操作。 JdbcRowSet ResultSet 对象的包装器使得将该结果集用作 JavaBeansTM 组件成为可能。 JdbcRowSet 是一个连接的 rowset,也就是说,它使用启用 JDBC 技术的驱动程序来维持它与 数据库的连接,所以它也能有效地使驱动程序成为 JavaBeans 组件。 因为它始终连接到其数据库,所以 JdbcRowSet 的实例可以简单地采用在其上进行调用的 方法,并依次对其 ResultSet 对象调用这些方法。因此,结果集可以是(举例来说)Swing 应用 程序中的一个组件。 JdbcRowSet 对象的另一个优点是可使用它让 ResultSet 对象可滚动和可更新 。默 认情况下,所有 RowSet 对象都是可滚动的和可更新的。如果使用的驱动程序和数据库不支持结 果集的滚动和 /或更新,则应用程序可以组装一个带 ResultSet 对象数据的 JdbcRowSet 对象, 然后在该 JdbcRowSet 对象上操作,就好像它是 ResultSet 对象一样。 JdbcRowSet 接口的参考实现 JdbcRowSetImpl 提供了默认构造方法的实现。使用默 认值初始化新的实例,可根据需要使用新值设置这些默认值。在调用新实例的 execute 方法之 前,它实际上无法真正发挥作用。通常,此方法执行以下操作: • 建立与数据库的连接 • 创建一个 PreparedStatement 对象并设置其所有占位符参数 • 执行语句来创建 ResultSet 对象 以下代码片断创建了一个 JdbcRowSetImpl 对象、设置命令连接属性、设置占位符参数,然 后调用方法 execute。 JdbcRowSetImpl jrs = new JdbcRowSetImpl(); jrs.setCommand("SELECT * FROM TITLES WHERE TYPE = ?");
  • 3. jrs.setURL("jdbc:myDriver:myAttribute"); jrs.setUsername("cervantes"); jrs.setPassword("sancho"); jrs.setString(1, "BIOGRAPHY"); jrs.execute(); SyncResolver, 当发生同步冲突时,它允许应用程序使用手工决策树来确定应该执行的操作。虽然应 用程序手工解决同步冲突并不是委托过程,但 此框架 还是提 供了一 些发生 冲突时 委托应 用 程序的方法。 冲突是指RowSet 对象的原始行值与数据源中的值不 匹配的情况,它 指示自最后一 次同步以来数据源行已被修改。 还要注意,RowSet 对象的原始值就是最后一次同步之前 的值,不必是其初始值。 SyncResolver 的 参 考 实 现 实 现 了 CachedRowSet 接 口 , 但 是 其 他 实 现 可 以 选 择 实 现 JdbcRowSet 接口,以满足特定的需要。 这一新的 SyncResolver 对象具有与 正在尝试 同步的 RowSet 对象相同的行数和列数 。 SyncResolver 对象包含数据源中导致冲突的值,其他值都为 null。另外,它包含关于每 个冲突的信息。 SyncResolver 对象(如 resolver)跟踪存在冲突的每个行中的冲突。它还可以锁定受 rowset 命令影响的表,以便在解决当前冲突时不再发生其他冲突。 可以从 SyncResolver 对象获取以下几种信息:  发生冲突时正试图进行的操作: SyncProvider 接口定义了四个常量来描述可能发生的状态。 //RowSet 对象正试图执行的操作类型 int operation = resolver.getStatus(); 第四个常量指示不存在冲突。  数据源中导致冲突的值 当 RowSet 对象更改并尝试写入到数据源的值自上一次同步以来也在数据源中被更改时, 会发生冲突。应用程序可以调用 SyncResolver 的方法 getConflictValue 来获取数据源中导 致冲突的值,因为 SyncResolver 对象中的值是取自数据源的冲突值。 java.lang.Object conflictValue = resolver.getConflictValue(2); 注意,resolver 中的列可以使用列号指定(如以上代码行中所示),也可以用列名称指定。 使用方法 getStatus 和 getConflictValue 获取到的信息,应用程序可以做出应在数据源中保 留哪一个值的决定。然后,应用程序调用 SyncResolver 对象的方法 setResolvedValue,它可以设置 RowSet 对象中和数据源中要保留的值。 resolver.setResolvedValue("DEPT", 8390426);
  • 4. 在以上代码行中,列名称指定 RowSet 对象中要使用给定值设置的列。也可以用列号来指定列。 解决当前冲突行中的所有冲突之后,应用程序会调用方法 setResolvedValue,并对 SyncResolver 对象中每个冲突行重复此过程。 要使导航 SyncResolver 对象更容易,尤其是存在大量没有冲突的行时,SyncResolver 接 口定义了方法 nextConflict 和 previousConflict,它们只移动到至少包含一个冲突值的行。 然后,应用程序通过提供列号作为参数调用 SyncResolver 的方法 getConflictValue,以获取 冲突值本身。 CachedRowSet CachedRowSet 对象 是 一 个 数 据行 的 容 器 , 可在 内 存 中 缓 存其 各 行 , 这 使得 进 行 操 作时无需总是连接到数据源。 此外,它还是一个 JavaBeansTM 组件,是可滚动、可更新、可序列化的。 CachedRowSet 对象通常包含结果集中的行,但它也 可 以 包 含 任 何 具 有 表 格 式 的 文 件 (如电子表格)中的行 。参考实现只支持从 ResultSet 对象中获取数据,但是开发人员可以 扩展 SyncProvider 实现,以提供对其他表格数据源的访问。 CachedRowSet 对象是一个 非连接 rowset,这意味着它只会短暂地连接其数据源。连 接数据源发生在读取数据以用各行填充自身,以及将更改传播回其底层数据源时。其余时间 CachedRowSet 对象是非连接的,包括修改它的数据时。非连接使 RowSet 对象更为简洁, 因此更容易传递给另一个组件。例如,非连接 RowSet 对象可以被序列化并通过导线传 递到瘦客户端 (thin client),如个人数字助理(personal digital assistant,PDA)。 使用参考实现 (RI) 中提供的默认 CachedRowSet 构造方法来创建默认的 CachedRowSet 对象。 可以实现 writer 以在检查和避免冲突方面实施不同程度的关注。( CachedRowSetImpl crs = new CachedRowSetImpl(); SyncProvider 对象提供了带有 reader 的(RowSetReader 对象)的 CachedRowSet 对象,用于从数据源读取数据以便用该数据填充自身。可以实现 reader 从 ResultSet 对象或者表格式的文件中读取数据。SyncProvider 对象还提供了 writer(RowSetWriter 对象),用于同步在与底层数据源中的数据断开连接时对 CachedRowSet 对象数据所做的任何更改。 应用程序可以找到已注册的 SyncProvider 实现。 java.util.Enumeration providers = SyncFactory.getRegisteredProviders();
  • 5. CachedRowSet 对象可使用两种方式来指定它将使用的 SyncProvider 对象。  向构造方法提供实现名 以下代码行创建 CachedRowSet 对象 crs2,使用默认值初始化该对象,但其 SyncProvider 对象是指定的。 CachedRowSetImpl crs2 = new CachedRowSetImpl( "com.fred.providers.HighAvailabilityProvider");  使用 CachedRowSet 方法 setSyncProvider 设置 SyncProvider 以下代码行为 crs 重置 SyncProvider 对象,该 CachedRowSet 对象是使用默认构 造方法创建的。 crs.setSyncProvider("com.fred.providers.HighAvailabilityProvider"); 获取 RowSetMetaData 通过在 RowSetMetaData 对象上调用 ResultSetMetaData 和 RowSetMetaData 的方法,应用 程序可以获得有关 CachedRowSet 对象中各列的信息。 RowSetMetaData rsmd = (RowSetMetaData)crs.getMetaData(); int count = rsmd.getColumnCount(); int type = rsmd.getColumnType(2); RowSetMetaData 接口与 ResultSetMetaData 接口有两方面不同。 • 它包括设置方法:当使用取自不同 ResultSet 对象的数据填充 RowSet 对象时,该 RowSet 对象在内部使用这些方法。 • 它包含较少的获取方法:某些 ResultSetMetaData 方法无法应用到 RowSet 对象。例如, 不会应用那些获取某个列值是可写入的还是只读的方法,因为 RowSet 对象的所有列要 么是可写入的,要么是只读的,这取决于该 rowset 是否可更新。 注 : 要 返 回 RowSetMetaData 对 象 , 实 现 必 须 重 写 java.sql.ResultSet 中 定 义 的 getMetaData() 方法返回 RowSetMetaData 对象。 更新 CachedRowSet 对象 更新 CachedRowSet 对象与更新 ResultSet 对象类似,但是因为更新 rowset 时它并未 连接到其数据源,所以必须执行额外的步骤才能使更改在底层数据源中生效。调用方法 updateRow 或 insertRow 后,CachedRowSet 对象还必须调用方法 acceptChanges 使更新写 入数据源。以下示例(其中指针在 CachedRowSet 对象 crs 中的行上)显示了更新当前行中 两个列值并同样更新 RowSet 对象的底层数据源所需的代码。 crs.updateShort(3, 58); crs.updateInt(4, 150000); crs.updateRow(); crs.acceptChanges(); 下一个示例演示了移至插入行、在插入行上构建新行、将新行插入 rowset,然后调用方法
  • 6. acceptChanges 将新行添加到底层数据源。注意,与获取方法一样,更新方法可以采用列索 引或列名来指定所操作的列。 crs.moveToInsertRow(); crs.updateString("Name", "Shakespeare"); crs.updateInt("ID", 10098347); crs.updateShort("Age", 58); crs.updateInt("Sal", 150000); crs.insertRow(); crs.moveToCurrentRow(); crs.acceptChanges(); 注:insertRow() 方法在何处插入 CachedRowSet 对象的插入行内容是由实现定义的 。 CachedRowSet 接口的参考实现紧随当前行插入新行,但也可以实现为在任何其他位置插入新行。 有关这些示例的另一个注意点是它们使用方法 acceptChanges 的方式。通过内部调用 RowSet 对象的 writer 将这些更改写入数据源,从而将 CachedRowSet 对象中的更改传播回底层数据 源的正是此方法。为此,writer 不得不承受建立到数据源的连接所带来的开销。上述两个代码片 断在调用 updateRow 或 insertRow 后立即调用方法 acceptChanges。但是,如果更改了多个 行,则更高效的做法是在调用所有 updateRow 和 insertRow 后再调用 acceptChanges。如果只调用 acceptChanges 一次,则只需要建立一个连接。 更新底层数据源 执行 acceptChanges 方法时,在后台调用 CachedRowSet 对象的 writer(一个 RowSetWriterImpl 对象),以便将对 rowset 所作的更改写入底层数据源。实现该 writer 以 建立到数据源的连接并写入更新。 可通过 SyncProvider 接口的实现提供 writer,这已第 1 部分“创建 CachedRowSet 对象”中讨论。默认的参考实现提供者 RIOptimisticProvider 会实现其 writer 使用乐观并发控制 (optimistic concurrency control) 机制。也就是说,在 rowset 与数据库断开时它不对底层数据库维持任何锁定,在将数据写入数据源之前它只是检查 是否有冲突。如果存在冲突,则不向数据源写入任何内容。 SyncProvider 类提供的 reader/writer 方法是可插入的,允许自定义数据的获取和更新。 如果需要其他的并发控制机制,可使用方法 setSyncProvider 插入其他 SyncProvider 实现。 要使用乐观并发控制例程,RIOptismisticProvider 要同时维护其当前值及其原始值(刚 好位于当前值之前的值)。注意,如果没有对 RowSet 对象中的数据进行任何更改,则其当前值 和原始值相同,都是最初填充 RowSet 对象时使用的值。但是,一旦更改了 RowSet 对象中的任 何值,当前值和原始值就不同了,尽管此时原始值仍是最初的值。随着后续对 RowSet 对象中的 数据进行更改,其原始值和当前值仍保持不同,但是其原始值将是前一个当前值。
  • 7. 关注原始值允许 writer 对 RowSet 对象的原始值和数据库中的值进行比较。如果 数据库中的值与 RowSet 对象的原始值不同,则意味着数据库中的值已经更改,出现了 冲突。writer 是否检查冲突、检查的程度如何,以及它如何处理冲突都取决于它的实现方式。 注册和通知侦听器 作为 JavaBeans 组件,参与 JavaBeans 事件模型的所有 rowset 都继承了用来注册侦听 器和用来通知这些侦听器 BaseRowSet 类中发生更改的各种方法。CachedRowSet 对象的侦听器 是一个组件,只要 rowset 中发生更改,它就应得到通知。例如,如果 CachedRowSet 对象包含 查询的结果,并且这些结果将以表格和条形图之类的形式显示,则可以向 rowset 将该表格和 条形图注册为侦听器,这样它们可以更新以反映各种更改。要成为侦听器,表格和条形图类 必须实现 RowSetListener 接口。然后可将它们添加到 CachedRowSet 对象的侦听器 列表,如以下代码行所示。 crs.addRowSetListener(table); crs.addRowSetListener(barGraph); 每个移动指针或更改数据的 CachedRowSet 方法也将更改通知已注册的侦听器,所以当 crs 中发生更改时 table 和 barGraph 将得到通知。 向瘦客户端传递数据 使用 CachedRowSet 对象的主要原因之一是要在应用程序的不同组件之间传递数据。因为 CachedRowSet 对象是可序列化的,所以可使用它(举例来说)将运行于服务器环境的企业 JavaBeans 组件执行查询的结果通过网络发送到运行于 web 浏览器的客户端。 由于 CachedRowSet 对象是非连接的,所以和具有相同数据的 ResultSet 对象相比更为简 洁。因此,它特别适于向瘦客户端(如 PDA)发送数据,这种瘦客户端由于资源限制或安全考虑 而不适于使用 JDBC 驱动程序。所以 CachedRowSet 对象可提供一种“获取各行”的方式而无需 实现全部 JDBC API。 滚动和更新 CachedRowSet 对象的第二个主要用途是为那些本身不提供滚动和更新的 ResultSet 对象提供这些功能。换句话说,当 DBMS 不提供对滚动和更新的完全支持时,可 使用 CachedRowSet 对象扩充启用 JDBC 技术的驱动程序(以下称为“JDBC 驱动程序”)的功 能。要使不可滚动和只读的 ResultSet 对象变得可滚动和可更新,程序员只需创建一个使用该 ResultSet 对象的数据所填充的 CachedRowSet 对象即可。以下代码片断演示了这一过程,其中 stmt 是一个 Statement 对象。 ResultSet rs = stmt.executeQuery("SELECT * FROM EMPLOYEES"); CachedRowSetImpl crs = new CachedRowSetImpl(); crs.populate(rs);
  • 8. 现在对象 crs 与对象 rs 一样,也包含了取自表 EMPLOYEES 的数据。不同的是 crs 的指 针可以向前、向后移动,或者移动到特定行,即使 rs 的指针只能向前移动也是如此。此外,即 使 rs 是不可更新的,crs 也将是可更新的,因为在默认情况下,CachedRowSet 对象是可滚动 和可更新的。 总之,可将 CachedRowSet 对象简单地看成是一个非连接的行集合,这些行将缓存在数据源外 部。由于它比较小并且是可序列化的,所以它可以轻松地通过导线发送,并且非常适合于向瘦客 户端发送数据。但是 CachedRowSet 对象也有局限性:它的大小限制在它一次可在内存 中存储的数据量范围内。 获得通用数据访问 CachedRowSet 类的 另 一 个 优 势在 于 它 能 够 从关 系 数 据 库 以外 各 种 数 据 源获 取 并 存 储数据。可以实现 rowset 的 reader 读取任何表格数据源(包括电子表格或平面文件)的数据, 并用该数据填充其 rowset。因为 CachedRowSet 对象及其元数据都可以从头创建,所以充 当 rowset 工厂的组件可以使用此功能来创建一个包含非 SQL 数据源数据的 rowset。但是 大部分情况下,希望 CachedRowSet 对象包含使用 JDBC API 从 SQL 数据库中获取的数据。 设置属性 如果某个 rowset 使用 DriverManager 设施建立连接,则它需要设置一个标识合适驱动 程序的 JDBC URL 属性,还需要设置那些提供用户名和密码的属性。另一方面,如果 rowset 使用 DataSource 对象 建 立 连 接 (这 是 首 选 的 方法 ) , 则 它 无需 设 置 JDBC URL 属 性。但是它需要设置用于数据源逻辑名、用户名和密码的属性。 分页数据 因为 CachedRowSet 对象在内存中存储数据,所以它在任一时间可以包含的数据量是由可用的 内存量决定的。要避开此限制,CachedRowSet 对 象 可 以 数 据 块 ( 称 为 页 ) 的 形 式 从 ResultSet 对象中获取数据。要利用此机制,应用程序应使用方法 setPageSize 设置一 页中要包括的行数。 换句话说,如果页大小设置为 5,则一次从数据源中获取一个 5 行的数据 块。应用程序也可选择设置一次可获取的最大行数。如果最大行数设置为 0,或者未设置最大行 数,则对一次获取的行数没有限制。 设置各个属性后,必须使用方法 populate 或方法 execute 用数据填充 CachedRowSet 对象。以下代码行演示了如何使用方法 populate。注意,该方法的这种形式采 用两个参数,ResultSet 句柄和 ResultSet 对象中的行,从该行开始获取各行。 CachedRowSet crs = new CachedRowSetImpl(); crs.setMaxRows(20); crs.setPageSize(4); crs.populate(rsHandle, 10); 运行此代码时,将使用 rsHandle 中从第 10 行开始的 4 行数据填充 crs。
  • 9. 下一个代码片断展示了如何使用方法 execute 填充 CachedRowSet 对象,该方法可以采用 Connection 对象作为一个参数,也可以不采用。此代码向 execute 传递 Connection 对象 conHandle。 注意,以下代码片断和上述代码片断有两处差别。首先,没有调用方法 setMaxRows,所以没有 对 crs 可以包含的行数设置限制。(记住,对于 crs 在内存中可以存储的数据量,总是有一个 最高限制。)第二个差别是不能向方法 execute 传递 ResultSet 对象中起始获取行的行号。此 方法始终从第一行开始获取。 CachedRowSet crs = new CachedRowSetImpl(); crs.setPageSize(5); crs.execute(conHandle); 运行此代码后,crs 将包含由 crs 的命令所生成的 ResultSet 对象中的 5 行数据。crs 的 writer 将使用 conHandle 连接数据源并执行 crs 的命令。然后应用程序就能够在 crs 中的数据上进行 操作,方式与在任何其他 CachedRowSet 对象的数据上进行操作的方式相同。 要访问下一页(数据块),应用程序可调用方法 nextPage。此方法创建新的 CachedRowSet 对象并用下一页的数据填充。例如,假定 CachedRowSet 对象的命令返回一个具 有 1000 行数据的 ResultSet 对象 rs。如果页大小设置为 100,则首次调用方法 nextPage 将 创建一个包含 rs 前 100 行的 CachedRowSet 对象。在使用这前 100 行的数据执行完所需的操 作后,应用程序可以再次调用方法 nextPage 创建另一个带有 rs 第二个 100 行数据的 CachedRowSet 对象。第一个 CachedRowSet 对象中的数据不再存在于内存中,因为它已被第二 个 CachedRowSet 对象的数据替换了。调用方法 nextPage 10 次后,第十个 CachedRowSet 对 象将包含 rs 最后 100 行存储在内存中的数据。在任意给定时间,内存中仅存储一个 CachedRowSet 对象的数据。 只要当前页不是各行的最后一页,方法 nextPage 就返回 true,没有其他页时,则返回 false。因此,可在 while 循环中使用它来获取所有页,正如在以下代码行中所演示的。 CachedRowSet crs = CachedRowSetImpl(); crs.setPageSize(100); crs.execute(conHandle); while(crs.nextPage()) { while(crs.next()) { . . . // operate on chunks (of 100 rows each) in crs, // row by row } } 运行此代码片断后,应用程序会遍历所有 1000 行,但是每次内存中的数据只有 100 行。
  • 10. CachedRowSet 接口还定义了方法 previousPage。正如方法 nextPage 类似于 ResultSet 方法 next,方法 previousPage 也类似于 ResultSet 方法 previous。与方法 nextPage 类似, previousPage 创建一个 CachedRowSet 对象,包含作为页大小设置的行数。因此,(举例来说) 方法 previousPage 可用在上述代码片断末尾的 while 循环中,以从最后一页开始逆向遍历到 第一页。方法 previousPage 也与 nextPage 类似,因为它也可以用在 while 循环中,不同之 处在于它是在前面还有页时返回 true,前面没有页时返回 false。 通过将指针定位于每页最后一行的后面(如以下代码片断所执行的),方法 previous 就可以 在每页中从最后一行遍历到第一行。代码也可将指针置于每页第一行的前面,然后在 while 循 环中使用 next 方法,以在每页中从最第一行遍历到最后一行。 以下代码片断假定是前一个代码片断的继续,这意味着第十个 CachedRowSet 对象的指针位于 最后一行。代码将指针移到最后一行的后面,这样第一次调用方法 previous 会将指针 放回到最后一行上。遍历最后一页(CachedRowSet 对象 crs )的所有行后,代码接着 会进入 while 循环以获得第九页、向后遍历各行、转至第八页、向后遍历各行,依此类推, 直到第一页的第一行为止。 crs.afterLast(); while(crs.previous()) { . . . // navigate through the rows, last to first { while(crs.previousPage()) { crs.afterLast(); while(crs.previous()) { . . . // go from the last row to the first row of each page } } WebRowSet 标准的 WebRowSet XML 模式定义位于以下 URI 中: http://java.sun.com/xml/ns/jdbc/webrowset.xsd 所有 WebRowSet 接口的标准实现必须使用该文档格式以确保互操作性。此外,WebRowSet 模式 使用特定的 SQL/XML 模式注释,从而确保较高的跨平台互操作性。目前 ISO 组织正在为此而努 力。SQL/XML 定义可从以下 URI 中得到: http://standards.iso.org/iso/9075/2002/12/sqlxml 模式定义从以下三个不同方面描述 RowSet 对象的内部数据:
  • 11. 属性 除了较为通用的 RowSet 属性之外,这些属性还描述标准同步提供者属性。 • 元数据 此项描述与 WebRowSet 对象管理的表格结构关联的元数据。描述的元数据与在 底层 java.sql.ResultSet 接口中可访问的元数据是紧密联系在一起的。 • 数据 此项描述原始数据(自从 WebRowSet 对象的上一次填充或上一次同步以来的数 据状态)和当前数据。通过跟踪原始数据和当前数据之间的 delta,WebRowSet 维持其 数据中的更改与原始数据源同步的能力。 FilteredRowSet 有时 RowSet 对象需要对其内容进行某种程度的过滤。一种可能的解决方案是为所有标准的 RowSet 实现提供一种查询语言;但是这对诸如非连接 RowSet 对象 之类的轻量级组件而言是 一种不切实际的方法。FilteredRowSet 接口寻求在不提供重量级查询语言和这种查询语言所需 处理的情况下解决这一需求问题。 JoinRowSet JoinRowSet 接口提供了一种机制,用于将取自不同 RowSet 对象的相关数据组合到一个 JoinRowSet 对象中,该对象表示一个 SQL JOIN。换句话说,JoinRowSet 对象可作为一个数据容 器,这些数据取自那些形成 SQL JOIN 关系的 RowSet 对象。 Joinable 接口提供了一些用于设置、获取和取消设置匹配列的方法 , 匹 配 列 建 立 SQL JOIN 关系的基础。通过将匹配列提供给恰当形式的 JointRowSet 方法 addRowSet 也可设 置匹配列。 无连 接的 RowSet 对象 ( CachedRowSet 对象和 扩展 CachedRowSet 接口的 实现) 没有一种能在 RowSet 之间建立 SQL JOIN 且无需 重新连接数据源(该操作开 销很大) 的标准方式。JoinRowSet 接口是专门为解决这一需求而设计的。 任何 RowSet 对象都可添加到 JoinRowSet 对象,以成为 SQL JOIN 关系的一部分。 可将任意数目的 RowSet 对象添加到 JoinRowSet 的实例中,前提是只要这些对象可以在 SQL JOIN 中关联起来。 Joinable 接口提供了用于建立公共属性的方法,可通过设置匹配列 来建立。匹配列通常与主 键相符,但是不要求匹配列与主键相同。通过建立然后强制执行匹配列, JoinRowSet 对象可 在 RowSet 对象之间建立 JOIN 关系,无需可用关系型数据库的协助。 可设置以下 SQL JOIN 类型: • CROSS_JOIN
  • 12. FULL_JOIN • INNER_JOIN - 未设置 JOIN 类型时使用的默认值 • LEFT_OUTER_JOIN • RIGHT_OUTER_JOIN 注意,如果未设置类型,则 JOIN 将自动为 INNER_JOIN。JoinRowSet 接口中各字段的注释说明 了这些 JOIN 类型,它们都是标准的 SQL JOIN 类型。 可用两种方式来设置匹配列: • 通过调用 Joinable 的方法 setMatchColumn 将 RowSet 对象添加到 JoinRowSet 对象之前,这是可以设置匹配列的唯一方法。为了 使用方法 setMatchColumn,RowSet 对象必须已经实现了 Joinable 接口。一旦设置了 匹配列值,则可在任意时间使用此方法来重置匹配列。 • 通过调用某种形式的 JoinRowSet 方法 addRowSet(使用列名或列号,或者列名数组 或列号数组) 5 个 addRowSet 方法中有 4 个采用匹配列作为参数。这 4 个方法可在将 RowSet 对 象添加到 JoinRowSet 对象时设置或重置匹配列。 以上具体示例请参见 jdk1.6 API javax.sql.包 JDBC