包 javax.sql.rowset.spi
RowSet
对象能够使用实现,供应商必须将其注册到 SyncFactory
单例。 (有关注册过程和要使用的命名约定的完整说明,请参阅 SyncProvider
的类注解。)
目录
1.0 封装规范
以下类和接口构成了 javax.sql.rowset.spi
包:
SyncFactory
SyncProvider
SyncFactoryException
SyncProviderException
SyncResolver
XmlReader
XmlWriter
TransactionalWriter
javax.sql
包中的以下接口也是 SPI 的一部分:
RowSetReader
RowSetWriter
SyncProvider
实现为断开连接的 RowSet
对象提供了将数据读入其中以及将其中已修改的数据写回基础数据源的机制。 Areader, RowSetReader
或 XMLReader
对象,在调用 CachedRowSet
方法 execute
或 populate
时将数据读入 RowSet
对象。 Awriter,一个 RowSetWriter
或 XMLWriter
对象,在调用 CachedRowSet
方法 acceptChanges
时将更改写回基础数据源。
将 RowSet
对象中的更改写入其数据源的过程称为同步RowSet
对象使用的 SyncProvider
实现决定了 RowSet
对象的编写器使用的同步级别。各种级别的同步被称为成绩.
较低级别的同步被称为乐观的并发级别,因为他们乐观地假设不会有冲突或冲突很少。当在 RowSet
对象中修改的相同数据在数据源中也被修改时,存在冲突。使用乐观并发模型意味着如果存在冲突,对数据源或 RowSet
对象的修改将丢失。
更高级别的同步称为悲观因为他们假设其他人将访问数据源并进行修改。这些等级设置不同级别的锁以增加不发生冲突的机会。
最低级别的同步只是将对 RowSet
对象所做的任何更改写入其基础数据源。编写器不执行任何检查冲突的操作。如果存在冲突并且数据源值被覆盖,则其他方对数据源所做的更改将丢失。
RIXMLProvider
实现使用最低级别的同步,仅将 RowSet
更改写入数据源。
对于下一层,编写器检查是否有任何冲突,如果有,它不会向数据源写入任何内容。这种并发级别的问题是,如果在RowSet
对象得到它的数据后,另一方修改了数据源中的相应数据,那么对RowSet
对象所做的更改就会丢失。 RIOptimisticProvider
实现使用此级别的同步。
在更高级别的同步(称为悲观并发)中,作者采取措施通过设置锁来避免冲突。设置锁的方式各不相同,从对单行设置锁到对表或整个数据源设置锁。因此,同步级别是用户并发访问数据源的能力与编写器保持 RowSet
对象中的数据及其数据源同步的能力之间的权衡。
要求所有断开连接的 RowSet
对象(CachedRowSet
、FilteredRowSet
、JoinRowSet
和 WebRowSet
对象)从 SyncFactory
机制获取它们的 SyncProvider
对象。
参考实现 (RI) 提供了两个同步提供程序。
RIOptimisticProvider
当未指定提供程序实现时,SyncFactory
实例将提供给断开连接的RowSet
对象的默认提供程序。
此同步提供程序使用乐观并发模型,假设访问数据库中相同数据的用户之间几乎没有冲突。它避免使用锁;相反,它会在尝试同步RowSet
对象和数据源之前检查是否存在冲突。如果存在冲突,它什么也不做,这意味着对RowSet
对象的更改不会持久保存到数据源。RIXMLProvider
可与WebRowSet
对象一起使用的同步提供程序,该对象是可以以 XML 格式写入或从 XML 格式读取的行集。RIXMLProvider
实现根本不检查冲突,只是将WebRowSet
对象中的任何更新数据写入基础数据源。WebRowSet
对象在处理 XML 数据时使用此提供程序。
SyncProvider
实现与参考实现捆绑在一起,这使得它们始终可用于 RowSet
实现。 SyncProvider
实现通过在 SyncFactory
单例中注册使自己可用。当 RowSet
对象请求提供者时,通过在构造函数中指定它或作为 CachedRowSet
方法 setSyncProvider
的参数,SyncFactory
单例检查请求的提供者是否已向其注册。如果有,SyncFactory
创建它的实例并将其传递给请求的 RowSet
对象。如果尚未注册指定的 SyncProvider
实现,则 SyncFactory
单例会导致抛出 SyncFactoryException
对象。如果未指定提供者,则 SyncFactory
单例将创建默认提供者实现的实例 RIOptimisticProvider
,并将其传递给请求的 RowSet
对象。
如果 WebRowSet
对象未在其构造函数中指定提供者,则 SyncFactory
将为它提供 RIOptimisticProvider
的实例。但是,WebRowSet
的构造函数被实现为将提供者设置为 RIXMLProvider
,它以 XML 格式读取和写入 RowSet
对象。
有关更多详细信息,请参阅 SyncProvider 类规范。
供应商可以开发具有任何一种可能的同步级别的 SyncProvider
实现,从而为 RowSet
对象提供同步机制的选择。
2.0 服务提供者接口架构
2.1 概述服务提供商接口提供了一种可插入机制,通过该机制可以注册SyncProvider
实现,然后在需要时生成。 SyncFactory
采用的惰性引用机制通过在断开连接的 RowSet
对象需要之前不创建实例来限制不必要的资源消耗。 SyncFactory
类还提供标准 API 来配置日志记录选项和流可能由特定的 SyncProvider
实现提供。
2.2 注册SyncFactory
第三方 SyncProvider
实现必须向 SyncFactory
注册,以便断开连接的 RowSet
对象获取它,从而使用其 javax.sql.RowSetReader
和 javax.sql.RowSetWriter
实现。以下注册机制可用于所有 SyncProvider
实现:
- 系统属性- 在命令行设置的属性。这些属性在运行时设置,并在每次调用 Java 应用程序时在系统范围内应用。请参阅 “相关文件” 部分了解更多相关信息。
- 属性文件- 在标准属性文件中指定的属性。这可以使用系统属性或通过修改位于平台运行时的标准属性文件来指定。该技术的参考实现包括一个标准属性文件,可以对其进行编辑以添加额外的
SyncProvider
对象。 - JNDI上下文可以在 JNDI 上下文中注册可用的提供者。
SyncFactory
将尝试加载绑定到上下文的SyncProvider
对象并将它们注册到工厂。必须将此上下文提供给SyncFactory
才能使机制正常运行。
SyncFactory
类描述中详细说明了如何在属性文件中指定系统属性或属性以及如何配置 JNDI 上下文。
2.3 SyncFactory Provider实例生成策略
如果提供商已正确注册,SyncFactory
会生成请求的 SyncProvider
对象。当使用指定的 SyncProvider
实现实例化断开连接的 RowSet
对象或在运行时使用替代 SyncProvider
对象重新配置时,将遵守以下策略。
- 如果指定了
SyncProvider
对象并且SyncFactory
包含no对提供者的引用,抛出SyncFactoryException
。 - 如果指定了
SyncProvider
对象并且SyncFactory
包含对提供者的引用,则提供请求的提供者。 - 如果未指定
SyncProvider
对象,则提供参考实现提供程序RIOptimisticProvider
。
这些策略在 SyncFactory
类中有更详细的探讨。
3.0 SyncProvider实施者指南
3.1 要求完全可插入 SyncFactory
的兼容 SyncProvider
实现必须扩展并实现 SyncProvider
类中的所有抽象方法。另外,一个实现必须确定 SyncProvider
类定义中定义的等级、锁定和可更新视图功能。一个或多个 SyncProvider
描述标准必须得到支持。预计供应商实现将提供一系列分级、锁定和可更新的视图功能。
此外,SyncProvider
命名约定必须按照 SyncProvider
类描述中的详细说明进行操作。
3.2 等级
JSR 114 定义了一组等级来描述 SyncProvider
对象可以提供断开连接的 RowSet
对象的同步质量。这些等级按照服务质量从最低到最高的顺序列出。
- GRADE_NONE不提供与原始数据源的同步。返回此等级的
SyncProvider
实现将简单地尝试将RowSet
对象中已更改的任何数据写入基础数据源,覆盖那里的任何内容。不会尝试将原始值与当前值进行比较以查看是否存在冲突。RIXMLProvider
是用这个等级实现的。 - GRADE_CHECK_MODIFIED_AT_COMMIT- 低等级的乐观同步。返回此等级的
SyncProvider
实现将检查在上次同步和当前正在进行的同步之间发生更改的行中的冲突。已修改的原始数据源中的任何更改都不会反映在断开连接的RowSet
对象中。如果没有冲突,RowSet
对象中的更改将写入数据源。如果存在冲突,则不会写入任何更改。RIOptimisticProvider
实现使用此等级。 - GRADE_CHECK_ALL_AT_COMMIT高等级的乐观同步。返回此成绩的
SyncProvider
实现将检查所有行,包括断开连接的RowSet
对象中未更改的行。这样,当同步成功完成时,对基础数据源中行的任何更改都将反映在断开连接的RowSet
对象中。 - GRADE_LOCK_WHEN_MODIFIED- 悲观的同步等级。返回此等级的
SyncProvider
实现将锁定原始数据源中与RowSet
对象中正在更改的行相对应的行,以减少其他进程修改数据源中相同数据的可能性。 - GRADE_LOCK_WHEN_LOADED- 更高的悲观同步等级。返回此等级的
SyncProvider
实现将锁定受用于填充RowSet
对象的原始查询影响的整个视图和/或表。
3.3 锁
JSR 114 定义了一组常量,这些常量指定是否在 RowSet
对象的基础数据源上放置了任何锁,如果是,则在哪些结构上放置了锁。当 RowSet
对象与数据源断开连接时,这些锁将保留在数据源上。
这些常量应该被认为是对等级常数的补充。大多数成绩设置的默认设置要求在RowSet
对象与其数据源断开连接时不保留任何数据源锁。 GRADE_LOCK_WHEN_MODIFIED
和 GRADE_LOCK_WHEN_LOADED
等级允许断开连接的 RowSet
对象对锁定程度进行细粒度控制。
- DATASOURCE_NO_LOCK- 原始数据源上没有任何锁。这是所有
SyncProvider
实现的默认锁定设置,除非RowSet
对象另有指示。 - DATASOURCE_ROW_LOCK- 锁定用于填充
RowSet
对象的原始 SQL 查询所触及的行。 - DATASOURCE_TABLE_LOCK在用于填充
RowSet
对象的查询触及的所有表上都放置了一个锁。 - DATASOURCE_DB_LOCK
RowSet
对象使用的整个数据源都被锁定了。
3.4 可更新视图
RowSet
对象可以填充来自 SQL VIEW
的数据。以下常量指示 SyncProvider
对象是否可以更新从中派生 VIEW
的一个或多个表中的数据。
- UPDATABLE_VIEW_SYNC表示
SyncProvider
实现支持与用于填充RowSet
对象的 SQLVIEW
派生的一个或多个表同步。 - NONUPDATABLE_VIEW_SYNC表示
SyncProvider
实现确实not支持与用于填充RowSet
对象的 SQLVIEW
派生的表同步。
3.5 SyncProvider
分级和锁定的使用
在下面的示例中,参考 CachedRowSetImpl
实现通过调用 setSyncProvider
方法重新配置其当前 SyncProvider
对象。
CachedRowSetImpl crs = new CachedRowSetImpl(); crs.setSyncProvider("com.foo.bar.HASyncProvider");应用程序可以检索当前由断开连接的
RowSet
对象使用的 SyncProvider
对象。它还可以检索提供程序实现的同步等级和当前使用的锁定程度。此外,应用程序可以灵活地设置要使用的锁定程度,这可以增加成功同步的可能性。这些操作显示在以下代码片段中。
SyncProvider sync = crs.getSyncProvider();
switch (sync.getProviderGrade()) {
case: SyncProvider.GRADE_CHECK_ALL_AT_COMMIT
//A high grade of optimistic synchronization
break;
case: SyncProvider.GRADE_CHECK_MODIFIED_AT_COMMIT
//A low grade of optimistic synchronization
break;
case: SyncProvider.GRADE_LOCK_WHEN_LOADED
// A pessimistic synchronization grade
break;
case: SyncProvider.GRADE_LOCK_WHEN_MODIFIED
// A pessimistic synchronization grade
break;
case: SyncProvider.GRADE_NONE
// No synchronization with the originating data source provided
break;
}
switch (sync.getDataSourceLock() {
case: SyncProvider.DATASOURCE_DB_LOCK
// A lock is placed on the entire datasource that is used by the
// RowSet
object
break;
case: SyncProvider.DATASOURCE_NO_LOCK
// No locks remain on the originating data source.
break;
case: SyncProvider.DATASOURCE_ROW_LOCK
// A lock is placed on the rows that are touched by the original
// SQL statement used to populate
// the RowSet object that is using the SyncProvider
break;
case: DATASOURCE_TABLE_LOCK
// A lock is placed on all tables that are touched by the original
// SQL statement used to populated
// the RowSet object that is using the SyncProvider
break;
也可以使用 SyncFactory
类中的静态实用程序方法来确定当前向 SyncFactory
注册的 SyncProvider
实现列表。
Enumeration e = SyncFactory.getRegisteredProviders();
4.0 解决同步冲突
接口SyncResolver
为应用程序提供了一种方法,可以在发生冲突时手动决定要做什么。当 CachedRowSet
方法 acceptChanges
完成并检测到一个或多个冲突时,它会抛出一个 SyncProviderException
对象。应用程序可以捕获异常并通过调用方法 SyncProviderException.getSyncResolver()
让它检索 SyncResolver
对象。
SyncResolver
对象是一种特殊的 CachedRowSet
对象或实现了 SyncResolver
接口的 JdbcRowSet
对象,逐行检查冲突。它是正在同步的 RowSet
对象的副本,只是它只包含来自数据源的数据,这导致了冲突。所有其他列值都设置为 null
。为了从一个冲突值导航到另一个冲突值,SyncResolver
对象提供了方法 nextConflict
和 previousConflict
。
SyncResolver
接口还提供了执行以下操作的方法:
- 找出冲突是否涉及更新、删除或插入
- 获取导致冲突的数据源中的值
- 如果需要更改,则设置应该在数据源中的值,或者如果需要更改,则设置应该在
RowSet
对象中的值
当调用 CachedRowSet
方法 acceptChanges
时,它委托给 RowSet
对象的 SyncProvider
对象。 SyncProvider
对象提供的 writer 的实现方式决定了冲突检查的级别(等级)。在完成所有冲突检查并发现一个或多个冲突后,acceptChanges
方法将抛出一个 SyncProviderException
对象。应用程序可以捕获异常并使用它来获取 SyncResolver
对象。
然后应用程序可以使用 SyncResolver
方法来获取有关每个冲突的信息并决定要做什么。如果应用程序逻辑或用户决定 RowSet
对象中的值应该保留,应用程序或用户可以用它覆盖数据源值。
SyncResolver
接口的注释有更多详细信息。
5.0 相关规范
6.0 相关文档
-
类描述服务提供商接口 (SPI) 机制生成
SyncProvider
实例以供断开连接的RowSet
对象使用。指示SyncFactory
机制的错误。为断开连接的RowSet
对象提供读取器/写入器功能的同步机制。表示SyncProvider
机制出错。定义了一个框架,允许应用程序使用手动决策树来决定在发生同步冲突时应该做什么。一个专用接口,有助于扩展标准SyncProvider
抽象类,使其具有更细粒度的事务控制。一个专门的接口,有助于扩展SyncProvider
面向 XML 的同步提供程序的抽象类。一个专门的接口,有助于扩展SyncProvider
面向 XML 的同步提供程序的抽象类。