Package javax.sql.rowset.spi
RowSet对象能够使用一个实现,供应商必须将其注册到SyncFactory单例中。(请参阅SyncProvider的类注释,了解注册过程和要使用的命名约定的详细说明。)
目录
1.0 包规范
以下类和接口组成了javax.sql.rowset.spi包:
SyncFactorySyncProviderSyncFactoryExceptionSyncProviderExceptionSyncResolverXmlReaderXmlWriterTransactionalWriter
javax.sql包中,也是SPI的一部分:
RowSetReaderRowSetWriter
SyncProvider实现为一个断开连接的RowSet对象提供了读取数据和将已修改数据写回底层数据源的机制。一个读取器,即RowSetReader或XMLReader对象,在调用CachedRowSet方法execute或populate时将数据读入RowSet对象。一个写入器,即RowSetWriter或XMLWriter对象,在调用CachedRowSet方法acceptChanges时将更改写回底层数据源。
将RowSet对象中的更改写入其数据源的过程称为同步。RowSet对象的写入器使用的同步级别由RowSet对象的写入器决定。各种同步级别被称为等级。
较低级别的同步被称为乐观并发级别,因为它们乐观地假设不会发生冲突或很少发生冲突。当在RowSet对象中修改的相同数据也在数据源中被修改时,就会存在冲突。使用乐观并发模型意味着如果存在冲突,则对数据源或RowSet对象的修改将会丢失。
较高级别的同步被称为悲观,因为它们假设其他人将访问数据源并进行修改。这些级别设置不同级别的锁,以增加冲突不发生的机会。
最低级别的同步仅是将RowSet对象中所做的任何更改写入其底层数据源。写入器不会检查冲突。如果存在冲突并且数据源值被覆盖,则其他方对数据源所做的更改将丢失。
RIXMLProvider实现使用最低级别的同步,只是将RowSet的更改写入数据源。
在更高级别的同步中,称为悲观并发,写入器会采取措施避免冲突,通过设置锁。设置锁可以从在单个行上设置锁到在表或整个数据源上设置锁。因此,同步级别是用户同时访问数据源的能力和写入器保持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,以使机制正常运行。
有关如何指定系统属性或属性文件中的属性以及如何配置JNDI上下文的详细信息,请参阅SyncFactory类描述。
2.3 SyncFactory提供程序实例生成策略
如果已正确注册提供程序,则SyncFactory将生成请求的SyncProvider对象。当实例化断开连接的RowSet对象时指定了特定的SyncProvider实现,或者在运行时使用替代的SyncProvider对象重新配置时,将遵守以下策略:
- 如果指定了
SyncProvider对象,但SyncFactory不包含对该提供程序的引用,则会抛出一个SyncFactoryException。 - 如果指定了
SyncProvider对象,并且SyncFactory包含对该提供程序的引用,则提供请求的提供程序。 - 如果未指定
SyncProvider对象,则提供参考实现提供程序RIOptimisticProvider。
这些策略在 SyncFactory类中有更详细的探讨。
3.0 SyncProvider实现者指南
3.1 要求一个符合标准的SyncProvider实现必须完全可插入到SyncFactory中,必须扩展并实现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实现不支持将数据同步到用于填充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
//一种乐观同步的高等级
break;
case: SyncProvider.GRADE_CHECK_MODIFIED_AT_COMMIT
//一种乐观同步的低等级
break;
case: SyncProvider.GRADE_LOCK_WHEN_LOADED
// 一种悲观同步等级
break;
case: SyncProvider.GRADE_LOCK_WHEN_MODIFIED
// 一种悲观同步等级
break;
case: SyncProvider.GRADE_NONE
// 不提供与原始数据源的同步
break;
}
switch (sync.getDataSourceLock() {
case: SyncProvider.DATASOURCE_DB_LOCK
// 在RowSet对象使用的整个数据源上放置锁
break;
case: SyncProvider.DATASOURCE_NO_LOCK
// 在原始数据源上不保留任何锁
break;
case: SyncProvider.DATASOURCE_ROW_LOCK
// 在由用于填充RowSet对象的原始SQL语句触及的行上放置锁
break;
case: DATASOURCE_TABLE_LOCK
// 在由用于填充RowSet对象的原始SQL语句触及的所有表上放置锁
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对象提供的写入器的实现方式决定将进行何种级别(等级)的冲突检查。在完成所有冲突检查并发现一个或多个冲突后,方法acceptChanges会抛出一个SyncProviderException对象。应用程序可以捕获异常并使用它来获取一个SyncResolver对象。
然后,应用程序可以使用SyncResolver方法获取有关每个冲突的信息并决定如何处理。如果应用程序逻辑或用户决定RowSet对象中的值应该是要持久化的值,则应用程序或用户可以用其覆盖数据源值。
SyncResolver接口的注释中有更多详细信息。
5.0 相关规范
6.0 相关文档
-
ClassDescription生成供断开的
RowSet对象使用的SyncProvider实例的服务提供者接口(SPI)机制。表示SyncFactory机制出现错误。为断开的RowSet对象提供读取/写入功能的同步机制。表示SyncProvider机制出现错误。定义了一个框架,允许应用程序使用手动决策树来决定在同步冲突发生时应该执行什么操作。一种专门的接口,促进了标准SyncProvider抽象类的扩展,使其具有更精细的事务控制。一种专门的接口,促进了针对XML导向同步提供程序的SyncProvider抽象类的扩展。一种专门的接口,促进了针对XML导向同步提供程序的SyncProvider抽象类的扩展。