跳至内容 Java Solaris 社区 Sun 商店 加入 SDN 我的个人档案 加入的益处
 
在 Sun Java Studio Creator 2 IDE 中使用 CachedRowSet 和 CachedRowSetDataProvider
 
作者:Joel BrownBeth Stearns,2006 年 2 月  
本技术文章介绍了如何在 Java Studio Creator IDE 中使用 CachedRowSet 和 CachedRowSetDataProvider 以编程方式将行插入到数据库表中。本文假定您对 CachedRowSet 和 CachedRowSetDataProvider 方法有了一定的了解。本文分为以下几部分。
 
目录
 
关于行集
应该使用 CachedRowSet 还是 CachedRowSetDataProvider?
两个代码示例
将行插入到数据库中的提示
详细信息
更多的开发者资源
 
 
关于行集
 
简单地说,CachedRowSet 用于存储从数据库中检索的数据;而 CachedRowSetDataProvider 是一个包装器,用于包装 CachedRowSet 中保存的数据。CachedRowSetDataProvider 的主要作用是可以在 IDE 中便捷地对组件进行绑定。实际上,CachedRowSetDataProvider 保存的唯一信息是光标在 CachedRowSet 中的位置。可以让多个 CachedRowSetDataProvider 实例引用相同的 CachedRowSet,每个实例可以在 CachedRowSet 中分别具有其自己的光标位置。
 
应该使用 CachedRowSet 还是 CachedRowSetDataProvider?
 
虽然 CachedRowSet 可以很好地执行将数据插入到数据库表中的操作,但是 CachedRowSetDataProvider 可以为您提供一种更简便的编码方法。您可以使用 CachedRowSetDataProvider 方法来访问 CachedRowSet,而不是直接对 CachedRowSet 进行编码。但是,无论是否使用 CachedRowSetDataProvider,都必须先创建 CachedRowSet。请记住,如果将数据库表放到页面上,IDE 将自动为该表创建 CachedRowSet(在会话 Bean 中)和 CachedRowSetDataProvider(在其页面中)。CachedRowSet 的 command 属性(即 SELECT 语句)可以为数据库 INSERT 操作提供键。

IDE 生成的表 INSERT 命令包含 CachedRowSet 的 command 属性中的所有列。例如,假设行集的 command 属性是 SELECT col1, col2 FROM mytable。此行集的 INSERT 命令将变为 INSERT INTO mytable(col1,col2) values(?,?)
 
两个代码示例
 
让我们看一下两个代码示例。代码示例 1 展示了如何使用 CachedRowSet 插入一行;而代码示例 2 展示了如何使用 CachedRowSetDataProvider 执行相同的插入操作。两个示例都假定您事先为数据库表创建了 CachedRowSet。此外,这些示例还假定页面中包含了一个消息组组件,用于向用户显示错误消息。请注意,通过对消息组组件的 errorinfo 方法的方法调用,可以向用户显示 CachedRowSet 或 CachedRowSetDataProvider 中抛出的任何错误。

首先,让我们了解一下使用 CachedRowSet 方法插入行时所需的操作。要使用 CachedRowSet 插入行,请先调用 execute 方法(如果尚未执行此操作),然后使用 moveToInsertRow 方法将 CachedRowSet 定位到正确的行上(execute 方法使用数据来填充 CachedRowSet 对象,方法是通过连接到数据库来读入数据,请注意,如果在提交任何重要的更新之前调用 execute 方法,将会丢失这些更新)。定位到正确的行后,使用不同的 CachedRowSet 更新方法(updateString、updateInt 等,具体取决于列类型)将列字段更新为新值,然后调用 insertRow 方法以插入该行。最后,请调用 CachedRowSet acceptChanges 方法将更新应用到数据源。如果发生冲突,则还必须捕获所有 SyncProvider 异常。捕获错误代码需要完成额外的工作才能构建有意义的消息。请参见代码示例 1。

CachedRowSet crs = getSessionBean1().getMyRowSet() ;
try { 
crs.execute() ;  // unless it's already been executed.
crs.moveToInsertRow() ;
crs.updateInt("COL1", 1 ) ;
crs.updateString("COL2","Row 1") ;
crs.insertRow() ;
crs.acceptChanges() ;
info("Row Inserted via CachedRowSet") ;
crs.release() ; // release rowset memory
} catch (SyncProviderException spe) {
try {
	// construct a message with all the possible
	// exceptions in the SyncProvider.Note that since
	// we're doing an INSERT, we should only care about
	// SyncResolver.INSERT_ROW_CONFLICT, but I'll handle
	// them all here.
	SyncResolver resolver = spe.getSyncResolver();
	String message = spe.getMessage() + ":";
	while(resolver!=null&&resolver.nextConflict())  {
		int row = resolver.getRow();
		if (!message.equals("")) {
			message += ";";
		}
		String zbrow = Integer.toString(row - 1) ;
		switch (resolver.getStatus()) {
			case SyncResolver.DELETE_ROW_CONFLICT:
				message += "DELETE_ROW_CONFLICT: " + zbrow ;
					break;
			case SyncResolver.INSERT_ROW_CONFLICT:
				message += "INSERT_ROW_CONFLICT: " + zbrow ;
				break;
			case SyncResolver.UPDATE_ROW_CONFLICT:
				message += "UPDATE_ROW_CONFLICT: " + zbrow ;
				break;
		}
		if (resolver instanceof SyncResolverX) {
			message += ": " + ((SyncResolverX)resolver).getSQLException() ;
		}
	}
	error( message ) ;
} catch (SQLException sqle) {
	error( sqle.getMessage() ) ;
   }
} catch (SQLException sqle) {
error(sqle.getMessage() ) ;
}
代码示例 1:使用 CachedRowSet 插入行

代码示例 2 说明了使用 CachedRowSetDataProvider 方法能够更简单地在数据源中插入行。首先,使用 appendRow 方法为 CachedRowSetDataProvider 附加一个空行。然后,调用 setCursorRow,将 CachedRowSetDataProvider 的光标定位到新行的位置。无论使用何种列类型,均使用相同的 setValue 方法来设置不同的列值。最后,调用 commitChanges 将更改提交到数据源中。只需使用一个简单的 catch 语句,即可捕获可能发生的所有错误。

您可以使用 CachedRowSetDataProvider.insertRow 方法在指定行之前插入新行,而不是附加一行。如果这样,则需要知道要插入的新行后面一行的 RowKey,并将该值作为参数传递给 insertRow 方法。

CachedRowSetDataProvider cdp = getMyDataProvider() ;
try {
	RowKey rk = cdp.appendRow() ;
	cdp.setCursorRow(rk) ;
	cdp.setValue("COL1", new Integer(1) ) ;
	cdp.setValue("COL2", "Row 1" ) ;
	cdp.commitChanges() ;
	info("Row Inserted via Data Provider") ;
		cdp.refresh() // release rowset memory.
} catch (Exception ee) {
	error( ee.getMessage() ) ;
}
代码示例 2:使用 CachedRowSetDataProvider 插入行

现在您已知道如何使用 CachedRowSet 和 CachedRowSetDataProvider 在数据库表中插入行了,您愿意使用哪种方法呢?特别是当两种方法都能完成此任务时,您应该选择一种最简便的方法。使用 CachedRowSetDataProvider 只会产生很小的开销,因此,请放心地使用它吧,它能带给您更简单易用的操作。
 
将行插入到数据库中的提示
 
无论使用哪种方法,将行插入到数据源时都需要注意一些问题。本部分列出了处理某些问题的一些提示。
  • 请记住,不论使用 CachedRowSet 还是 CachedRowSetDataProvider 来插入行,插入操作就是执行行集命令。因此,如果使用行集是为了插入行,则 SELECT 命令不应执行任何额外的处理或检索任何数据。例如,使用 SELECT col1, col2 FROM mytable WHERE 0=1。如果不想执行 SELECT 语句,则无法使用 CachedRowSet,而是,需要使用无格式的旧 JDBC 代码。

  • 您可能想了解 CachedRowSet 是如何知道 INSERT 语句中包含了哪些列。Java Studio Creator 会根据数据库驱动程序并通过 preparedStatement.getMetaData 方法来确定可写的列。如果行集 SELECT 语句中包含计算列,则需要引起注意。计算列将被忽略,并且不包含在 INSERT 语句中。同时,不是所有的数据库驱动程序都会返回完整的、甚至是正确的元数据,这会影响 INSERT 语句的正确性。

  • 有时您可以使用现有的 CachedRowSet 将行插入到数据源中,有时则需要您创建一个新的 CachedRowSet 进行插入。下面提供了一些准则来帮助您作出选择:

    • 如果现有的 CachedRowSet 包含了所有需要插入的列,则应考虑使用该 CachedRowSet。如果它包含了不需要插入的列,则会出现问题。

    • 也可以使用为读取或显示数据而创建的现有 CachedRowSet 来插入数据。如果执行此操作,请牢记前面提到的关于计算列的注意事项。另外,如果表包含一个不为空的列并且该列在行集中,则插入将会失败。

    • 您可以使用现有的 CachedRowSet 来插入数据行,即使 CachedRowSet 引用了多个表。插入操作只会影响单个表,这是由行集的 tableName 属性决定的,而会忽略所有其他表及其列。

  • 表包含数据库生成的列(如 IDENTITY 和 AUTOINCREMENT)时,请一定要注意。数据库生成列的行为通常是针对特定的数据库的。在某些情况下,您可能需要通过某些特定于供应商的方法来获取插入操作的键。在其他情况下,您可能需要将列值设置为 Null,或者在 INSERT 语句中不包括该列。

  • 如果使用 INSERT 操作产生了数据库生成的值,则可以通过重新选择该数据来检索这些值。即必须调用 SELECT 命令以查找生成的值。

  • CachedRowSet 实现为您生成了 SQL 语句,您可以在应用服务器的日志文件中查看这些语句。要将生成的 SQL 语句记录到此文件中,请将行集的 printStatements 属性设置为 true。在“概要”窗口中,选择 SessionBean1(或 ApplicationBean1)中的行集以打开其“属性”窗口。您可以在行集“属性”窗口的“高级”类别中找到 printStatements 属性。请参见图 1。

    图 1:行集属性表单
  • 您可以通过编程方式从 INSERT 语句中排除某个特定的列。例如,需要排除 IDENTITY 列。要排除某个列,则需要使用行集的 insertableColumns 属性。由于当前不支持使用 IDE 的属性表单来设置该属性,因此必须在 Java 代码中通过布尔值数组来设置 insertableColumns 属性值。请创建一个布尔值数组,该数组为表中的每列都包含一个值,即数组中的每个值对应于表中的一列。要在 INSERT 语句中包含一列,请将其对应的数组布尔值设置为 true;要排除一列,请将其对应的数组值设置为 false(图 1 表明您可以在行集属性表单的“高级”类别中看到 insertableColumns 属性的值)。

  • 您可以覆盖 CachedRowSet 标准异常消息,但要求您解释 SQLException 消息并创建您自己的消息。抛出 SyncProviderException 时,该异常将显示行集中发生错误的行及其 SQLException。如果使用的是 CachedRowSetDataProvider,则需要解析其异常消息文本。但要记住,如果更新或插入了多行,则异常会包含多个错误消息。
 
详细信息
 

要获取有关 CachedRowSet 的详细信息,请通过 Java Studio Creator 的“帮助”菜单或“动态帮助”窗口来参阅行集的 Javadoc API 引用。同时也可以参阅 JDBC Javadoc,但 Java Studio Creator 的 CachedRowSet 接口实现方式略有不同。

有关 CachedRowSetDataProvider 的详细信息,可以参阅同一“动态帮助”窗口(或使用“帮助”菜单)中的 Javadoc 数据提供器 API 引用。请参见图 2。

图 2:Javadoc 的动态帮助

还应该访问 Joel 的有关使用 CachedRowSet 和 CachedRowSetDataProvider 的博客文章:http://blogs.sun.com/roller/page/jfbrown

 
更多的开发者资源
 

有关为开发者提供的更多技术提示、文章和专家建议,请访问 Sun Developer Network (SDN) 上的 Java Studio Creator 开发者资源,网址为:http://gceclub.sun.com.cn/prodtech/javatools/jscreator/


Joel Brown 专门研究数据库方面的内容,他负责了大部分的 Creator IDE 的数据库工作。他在使用数据库和编写业务应用程序方面已有 20 多年的经验。
 
Beth Stearns 撰写了许多有关 Java 技术的文章和书籍。最近,她与别人合著了一本有关 J2EE BluePrints 的书《Designing Web Services with the J2EE 1.4 Platform》(使用 J2EE 1.4 平台设计 Web 服务)。