XPage 对于 Domino 开发人员的一大好处就是能够很方便和高效的访问关系型数据库。本文通过实例代码展现了在 XPage 中访问关系型数据库的具体步骤 , 同时讲解了一些在 XPage 中高效访问关系型数据库的技术,例如通过使用连接池提供访问的效率。最后文章会对关系型数据库的访问的最佳实践做一些讨论。
XPages 访问关系型数据库技术与最佳实践
我们在进行 XPages 应用开发的时候,有时一些事务性数据存在关系型数据库中,或者要集成其他系统中的数据,需要访问关系型数据库中的数据。XPages 本身是一个基于 Java 的服务器,所以它在访问关系型数据库时非常方便。
做为一个 Java 的开发人员,我们完全可以直接在 XPages 中通过 JDBC 访问关系型数据库。为了我们更方便的访问关系型数据库,并且紧密的与 Xpages 的控件集成,XPages 扩展库(XPages Extension Library)提供了访问关系型数据库的插件。通过使用 Xpages 扩展库中关系数据库的功能,我们能够非常容易并且高效的访问关系型数据库,而且能够直接将关系型数据库中的数据直接在界面控件中进行展示。本文将主要介绍如何使用 Xpages 扩展库来访问关系型数据库及最佳实践。
简介
XPages Extension Library(XPages 扩展库)是 XPages 开发团队开发和维护的一个扩展 XPages 功能的控件库。它不仅提供了一系列功能强大的界面控件,同时也提供一些 XPages 基础功能的增强,例如对关系型数据库访问,Rest 服务的访问,OAuth 认证等。XPages 扩展库开始作为一个开源项目发布在 OpenNTF.org 上,很快由于开发者对它的好评,Domino 9.0 已经将扩展库中的核心功能集成进来。
在 XPages 扩展库中,与关系型数据库访问相关的主要有两个插件: com.ibm.xsp.extlibx.relational com.ibm.xsp.extlibx.relational.derby 插件 com.ibm.xsp.extlibx.relational 包含了所有关系型数据库访问的实现,com.ibm.xsp.extlibx.relational.derby 作为一个封装 JDBC 驱动程序的例子,其中打包了关系型数据库 Derby 的 JDBC 驱动程序。
在插件 com.ibm.xsp.extlibx.relational 中,它是直接使用 JDBC API 访问关系型数据库的,不需要与 NSF 数据库同步,所以它的效率极高。同时,它也实现了一个 JDBC 的连接池,所有与数据库的连接都可以使用连接池中的 JDBC 连接,这样可以大大提供数据库访问的效率。为方便界面控件展示关系型数据库中的内容,它也将 SQL 查询或者关系型数据库表封装成了 XPages 的数据源,这样我们展示关系型数据库中的内容和展现 Domino 数据库中的内容一样简单。它也提供了一组 Java 和 Javascript 的 API,我们可以直接在程序中使用这些 API 来访问 JDBC。下面我将一步步介绍其安装配置方法以及如何使用。
作者: oreilly 时间: 2014-2-12 11:19
安装配置方法 我们要使用扩展库中的关系型数据库访问功能,首先需要将 XPages 扩展库安装到 Designer 和 Domino 服务器上。安装方法非常简单,参见 XPages 扩展库文档。安装完扩展库后,我们需要安装 JDBC 的驱动程序,然后配置数据库连接。下面我们一一介绍。 JDBC 驱动程序安装方法 JDBC 驱动程序实际上是一个 Java 库,一般就是一个 Jar 文件,我们可以通过以下三种方式来安装到 Domino 服务器中: 标准 JDBC 安装方法(不推荐使用):将 JDBC 驱动程序 jar 文件放到 Domino 自带的 JAVA 虚拟机的 jvm/lib/ext 目录中; 将 JDBC 驱动程序 Jar 文件放到 NSF 数据库中(不推荐使用):这样每一个 NSF 数据库都将加载自己的 JDBC 驱动程序,如果多个 NSF 数据库都加载同样的 JDBC 驱动程序,可能会有冲突,另外这需要应用程序自己注册 JDBC 驱动程序; 将 JDBC 驱动程序封装为 OSGI 插件(推荐使用):这样可以自动注册 JDBC 驱动程序,不同数据库应用间可以共享 JDBC 驱动程序从而提高性能 下面我们介绍如何将一个 JDBC 驱动程序封装成为一个 OSGI 的插件以方便我们在 XPages 中使用: 首先使用 Designer 或者 Eclipse 创建一个 OSGI 的插件; 在插件的根目录中创建一个 plugin.xml 文件,并加入如下扩展点,将 JDBC 驱动程序的类名写入: <?xml version="1.0" encoding="UTF-8"?> <plugin> <extension point="com.ibm.commons.Extension"> <service type="com.ibm.common.jdbcprovider" class="JDBC驱动程序类名" /> </extension> </plugin> 在插件中创建一个 lib 目录,将 JDBC 驱动程序的 Jar 文件拷贝到插件的 lib 目录; 修改 OSGI 插件的 META-INF/MENIFEST.MF 文件 修改文件中对应 Bundle-ClassPath 属性行,将 JDBC 驱动 Jar 文件加入插件 classpath: Bundle-ClassPath: ., lib/jdbc 驱动程序文件名.jar 修改文件中 Export-Package 属性,将 JDBC 驱动程序所用到的所有类名导出,以下以 derby 数据库为例: Export-Package: com.ibm.xsp.extlib.relational.derby, org.apache.derby.authentication,
org.apache.derby.catalog, org.apache.derby.catalog.types,
… 修改文件中的 Require-bundle 属性,加入 JDBC 驱动程序运行所需要依赖的其他插件:Require-Bundle: com.ibm.commons.jdbc 这样我们就可以将一个 JDBC 的驱动程序封装成为一个 OSGI 的插件。我们可以在 Designer 或 Eclipse 中将插件导出成一个 Jar 文件。需要使用时,我们只要将插件对应的 jar 文件拷贝到 Domino 的 data\domino\workspace\applications\eclipse\plugins 目录就可以了。 数据库连接设置 我们连接关系型数据库时,我们需要指定连接的关系型数据库服务器,所用的驱动程序,用户名和密码等。在 XPages 扩展库的数据库访问插件中 , 可以通过 JDBC 连接文件来指定这些信息。XPages 扩展库中的数据库访问插件会读取 *.jdbc 的连接文件,然后创建相应的数据库连接以供应用程序使用。 我们可以将数据库连接文件 *.jdbc 放于不同位置,分别对应不同的作用域: 全局 JDBC 连接:在 Domino/data/properties 文件夹中添加 *.jdbc 文件 NSF 数据库中 JDBC 连接:在数据库的目录 WebContent/WEB-INF/ 文件夹中添加文件夹 jdbc,然后在 jdbc 中添加 *.jdbc 文件 全局 JDBC 连接可以为 Domino 服务器上的所有应用所使用,而 NSF 数据库中的 JDBC 连接只能为单个 NSF 应用所使用。 JDBC 连接文件使用一种类似 XML 的格式,用于定于 JDBC 连接参数,如 JDBC URL, 数据库用户名、密码。数据库访问插件会读取这些 *.jdbc 的连接文件,解析其内容,创建连接池,并且将连接通过 JNDI 暴露出来,对应的 JNDI 的名字为:jdbc/{ 文件名 }。开发人员也可以直接通过 JNDI 的 API 来获取相应连接。连接文件中有四个属性可以设置: Driver:JDBC 驱动程序的类全名 Url:JDBC URL,用于指定 JDBC 驱动类型和服务器地址等 User:用于访问关系型数据库的用户名 Password:用于访问关系型数据库的用户名对应密码 下面是一个样例 jdbc 连接文件,我们可以参照它来写自己的 JDBC 连接文件: <jdbc> <driver>org.apache.derby.jdbc.EmbeddedDriver</driver> <url>jdbc:derby:${rcp.data}\derby\XPagesJDBC;create=true</url>
<user>phil</user> <password>phil</password> </jdbc>
作者: oreilly 时间: 2014-2-12 11:20
使用方法
一旦我们安装了 JDBC 驱动程序,并且配置好了数据库连接文件,我们就可以在应用中访问关系型数据库了。我们可以通过两种方式来访问:
- 在界面控件中使用 RDBMS 数据源
- 在 Java 或 Javascript 代码中使用 API
第一种方式可以让我们非常方便的在界面控件中展示关系型数据库中的数据,第二种方式更加灵活和强大,我们可以根据实际情况选用不同的使用方式。
RDBMS 数据源
XPages 扩展库中的数据库访问插件提供了两种数据源,它们和系统提供的 Domino 视图数据源一样,可以为 ViewPanel 等容器控件提供数据,不需要编程。这两种数据源分别为:
- jdbcQuery:只读型数据源,直接使用JDBC结果集(Result Set),必要时使用缓存
- jdbcRowSet:可读写数据源,使用 JDBC CachedRowSet,获取所有结果,在数据改动提交回RDBMS之前缓存所有改动,使用一个自定义的处理器解决更新冲突。 图 1. 关系型数据库数据源
数据源有一系列的属性用于指定数据的来源以及数据访问方式,下面我们了解一下其中最重要的几个。
首先需要指定的是数据库连接,数据源可以设置为使用一个预定义的数据库连接或一个 JDBC URL:
- 通过属性 connectionName 来指定预定义的数据库连接名称,强烈建议使用预定义的数据库连接以使用连接池提高性能,这样也易于管理
- JDBC URL 通过属性 connectionUrl 指定,仅仅为了调试时使用图 2. JDBC URL
然后我们需要指定数据库查询条件,我们可以通过以下三种方式指定查询条件:
- 通过属性 sqlTable 指定查询的数据库表,运行时会生成查询语句:select * from <table name>
- 通过 sqlQuery 属性指定一个数据查询语句,查询语句可以是静态的,也可以是动态生成的
- 通过 sqlFile 属性指定一个包含 sql 查询语句 *.sql 资源文件,对应的sql文件必须放在文件夹 WebContent/WEB-INF/jdbc 下
这三个属性如下图所示:
图 3. 关系型数据库数据源查询条件属性
如果我们通过以上的 sqlQuery 属性来指定一个查询语句,我们可以使用动态查询语句,也就是SQL查询语句中可以使用“?”来动态设定查询参数。我们可以通过属性 sqlParameters 来指定匹配的参数值。设置方式如下:
图 4. 关系型数据库数据源的 sqlParameters 属性
如果使用翻页器控件,必须知道结果集大小以显示正确的页数。我们可以通过将属性 calculateCount 设置为 true 来启动这一功能。缺省启动这一功能后将隐式的创建一条查询语句 select count(*) 来获取结果集大小。隐式生成的查询语句只是将原有的查询语句的查询部分改成 count(*) 来生成结果集大小查询语句。也可以通过属性sqlCountQuery来指定一个自定义的结果集大小查询语句,比如可以去掉查询语句中的排序等条件提高效率。
数据源 jdbcQuery 有一些特有的属性:
- maxBlockCount:数据源 jdbcQuery 是将 SQL 查询结果按块缓存到内存中的,缺省缓存块数为 0,可以通过属性 maxBlockCount 来指定用于缓存的内存块数目
- orderBy:可以通过属性 orderBy 来指定排序列
数据源 jdbcRowSet 也有类似的属性:
- maxRows:执行完查询后缺省会将所有查询结果保存到内存中,可以通过属性 maxRows 指定最多缓存的结果行数
在使用数据源 jdbcRowSet 时,我们有时候需要使用程序来执行一些操作,比如保存修改,创建新的行,这时需要使用 jdbcRowSet 的数据对象。在我们创建一个 jdbcRowSet 数据源时,我们可以通过 var 属性指定 jdbcRowSet 数据对象名,如下:
<xe:jdbcRowSet connectionName="derby1" var="jdbcData1" sqlTable="users" showDeleted="true"> </xe:jdbcRowSet>
一旦设置了数据对象名称之后,我们就可以使用 Java 和 javascript 代码来操作改对象了,其中可是使用的主要方法如下:
- jdbcData1.acceptChanges()
- jdbcData1.saveRow(row)
- jdbcData1.getRow(int)
- jdbcData1.newRow()
我们在访问关系型数据库时有一个非常重要的概念:事务。当我们在使用数据源时,缺省数据源自动提交所有改动,既每一个数据源每次数据操作都在一个事务中。有时我们希望多个数据源的数据操作参与到同一个事务中,既同时提交或者回滚。这时我们可以使用一个事务管理控件(JDBC Connection Manager)来控制事务提交,可以允许多个数据源参与同一个事务。使用时,只要将 jdbcConnectionManager 控件添加到 XPage,并且指定 ID 和 JDBC 连接名:
<xe:jdbcConnectionManager id="jdbcConnectionManager1" connectionName="derby1"> </xe:jdbcConnectionManager>
另外在数据源属性中指定使用的 JDBC Connection Manager 控件 ID:
<xe:jdbcQuery var="jdbcData1" connectionManager="jdbcConnectionManager1">
这样,所有指定同一个 JDBC Connection Manager 的所有数据源所对应的数据操作将被放到同一个数据库事务中执行。
API
除了数据源这种方式外,XPages 扩展库中的关系型数据库插件也提供了一组 Java 和 Javascript API 以方便我们获取 JDBC 连接和一些简单的 JDBC 操作等。一旦我们获取到 JDBC 的连接,我们就可以直接调用 JDBC API 来操纵数据库了。
首先,数据库插件提供了一个 JdbcUtil 的类,在 Java 中我们可以直接调用 JdbcUtil 的方法来创建、获取 JDBC 连接等:
public static Connection createConnectionFromUrl(FacesContext context, String connectionUrl):从一个 JDBC 连接 url 创建一个 JDBC 连接;
public static Connection getConnection(FacesContext context, String name): 根据连接名获取一个 JDBC 连接,这些连接名都是由 *.jdbc 连接文件所定义的;
public static IJdbcConnectionManager findConnectionManager(FacesContext context, UIComponent from, String name):获取连接管理器;
另外,包 com.ibm.xsp.extlib.jdbc.dbhelper.DatabaseHelper 中封装了一些 SQL 语法,方便我们使用 Java 代码创建 SQL 语句,而不是直接写 SQL 文本。
以上的 Java API,在 Javascript 中都可以直接调用。另外,我们也提供了一套以 @Jdbc 为前缀的函数 :
- 可以获取 JDBC 连接:@JdbcGetConnection
- 可以执行 SQL 语句: @JdbcExecute, @JdbcInsert,@JdbcUpdate,@JdbcDelete
作者: oreilly 时间: 2014-2-12 11:23
使用限制 我们在使用 RDBMS 数据源的时候有一些限制如下: RDBMS 数据源只支持基本的 SQL 类型,不支持 Blob, Stream, Array, Struct,但是这些可以通过 JDBC 方法直接调用; 控件 FileUpload 和 FileDownload 不能直接绑定到关系型数据源 没有对 JTA 和分布式事务专门的支持,需要自己通过 Java 代码实现 Apache DBCP 暂时没有启用
最佳实践 为了获取最好的性能和最佳的效果,我们在开发与关系型数据库集成的应用中最好能遵守以下几点: 通过 OSGI 插件方式提供 JDBC 驱动程序,这样所有的应用可以共享驱动,避免了驱动程序多次加载、冲突等问题; 如果可能的话尽可能使用定义全局 JDBC 连接,这样不同 NSF 应用可以共享同样的连接以提高性能; 对于关系数据库表或视图数据的简单显示和修改可以直接使用关系数据源 jdbcQuery 或 jdbcRowSet,这样不仅代码简单,不容易出错 数据源 jdbcRowSet 适合数据量少的情况,否则会占用大量内存 尽量从数据库连接池获取连接以提高性能,特别是使用 Java 代码访问数据库时,一定要通过 JdbcUtil 中的方法获取连接,这样才能从已有的连接池中获取连接。 对于复杂的关系型数据访问和计算,可以直接使用提供的 Java API 来直接调用 JDBC 实现
总结 以上我们介绍了 XPages 扩展库中关系型数据库访问插件以及如何使用,有了这些基础的支持,我们可以非常方便的集成关系型数据库中的数据到 XPages 中来。
作者:梁 骞, 顾问软件工程师, IBM 原文地址:http://www.ibm.com/developerwork ... ages-rdb/index.html