在开发分布式应用程序时可用性与性能是主要考虑事项但是用数据存储解决这些问题可能会给异构数据存储之间的数据同步带来一些问题在本文中Jayanthi Suryanarayana 和 Neil Tunnicliffe 将提供一种解决方案用 JDBC 和 SyncML 标准来实现通用的数据库数据复制
在设计分布式应用程序时必须考虑可用性与性能一般的解决方案是在客户机系统上包含数据存储通常由于资源有限客户机需要一个轻量级数据存储这种方法为异构数据存储之间的数据同步带来了挑战这个问题的一种解决方案是采用基于 java 的方法用 JDBC 和 SyncML 标准进行异构数据库复制
复制概述
复制是在两个环境之间复制全部或部分数据库的过程为了保持一致对源数据库所做的更改要传播到复制的数据库中复制可以是单向的也可以是双向的双向复制可能更困难一些因为对任何数据库所做的更改都可能产生不一致的数据当这些更改在两个数据库之间传播时需要有一个策略来调解这些差异以便维护一致性
ID 处理
作为复制的基本需求我们需要惟一地标识将要复制的每个数据单元对于双向复制还需要一个能够标识数据库之间对应数据单元的映射方案根据复制的需求可以采用各种各样的方案对于单向复制主数据库可以要求为数据单元生成 ID对于双向复制必须根据应用程序的 ID 生成方案定义映射方案ID 生成方案与映射方案可以是每个数据库使用的 ID 编号的相互排斥范围在这个范围内ID 编号是正好匹配的更复杂的示例中可能包括 ID 生成服务或者特定于数据库的方案在这种情况下必须在数据库之间维护 ID 的映射
变化检测
复制过程中的下一步是找出哪些数据单元已经更改在关系数据库中可以用附加字段来记录数据单元的状态和状态变化的时间戳或者也可以使用触发器使部分变化检测过程自动化附加到表上的插入/更新/删除触发器可以检测到对数据单元所做的更改并在更改日志表中记录这些更改这样就可以用变更记录表(change log table)确定在任何指定时间上对数据单元所做的更改
复制
复制的目标是产生公共数据集的多个一致的副本为了实现这个目标必须交换每个数据库中检测到的更改并使它们一致在这里您面临着一个设计上的挑战您可以作出如下选择
表示将交换的那些更改的数据格式
传输机制例如 HTTPFTPJMS 等取决于应用程序的需求
参与实体之间的交换协议
数据单元之间的沖突检测和解决机制
SyncML 定义了一个同步协议使用 XML 消息来添加删除和修改数据单元它也允许交换安全信息这样节点就可以执行身份验证
SyncJ 是 SyncML 的开源 java 实现它能够支持多种传输机制SyncJ 也根据应用程序的需求给出了沖突检测框架和解决策略
示例实现
本文将介绍一个简单的数据复制示例这个示例将演示两个异构数据库之间的双向客户数据记录复制每个数据库都包含一个结构类似的客户表使用惟一的客户 ID 来标识被复制的每条记录我们在表中添加了两列以记录每条记录的状态和最后状态变化时间戳对于这个示例状态与时间戳这两列必须通过应用程序或手工进行填充正如前面说过的触发器是一种在变更记录表中自动填充更改数据的适当解决方案但是在这个例子中使用的数据库目前拥有的触发器能力还很有限因此我们选择不用触发器来实现这项任务而且这个实例不包括双向复制的沖突解决策略所以沖突会导致复制过程失败
我们要配置在 Tomcat servlet 容器中运行 SyncJ 服务器的服务器端环境还要用 Derby 作为源数据库此外还要配置客户端环境用 HSQLDB 作为目标数据库在上面运行 SyncJ 客户程序(在这个例子中假设已经安装了 JSE SDK 和 Ant)
服务器端安装
要运行示例应用程序需要在服务器端安装三个开源组件TomcatSyncJ 服务器和数据库引擎安装 TomcatSyncJ 和 Derby 按以下步骤安装三个主要的服务器组件(请参阅 参考资料以获得下载链接)下载并展开 Tomcat 本文中用 TOMCAT 表示 Tomcat 的安装目录将环境变量 JEE_HOME 设为 TOMCAT下载并展开 SyncJ Server 本文中用 SYNCJ 表示 SyncJ 服务器的安装目录下载并安装 Derby本文中用 DERBY 表示 Derby 的安装目录
配置示例应用程序
接下来需要配置示例代码请单击本文顶部或底部的 Code 图标来下载jsyncjzip将该文件解压到包含本示例使用的客户端代码服务器代码和 SQL 脚本的目录中本文中用 TESTSYNC 表示这个目录
设置 JDBC 驱动程序类路径
设置 JDBC 驱动程序的类路径将 dbjccjar 和 dbjcc_license_cjar 分别从 DERBY\lib 复制到 TOMCAT\common\lib 和 SYNCJ\lib 中用于 SyncJ 服务器的 Derby 安装脚本接下来将目录 TESTSYNC\derby 移动到 SYNCJ\default\sql提供的脚本与 SyncJ 服务器下载一起提供的其他数据库脚本类似但是要针对 Derby 对它们稍作修改构建示例 SyncJ 服务器模块要构建示例 SyncJ 服务器模块请按以下步骤进行
将 TESTSYNC\module\buildbat 中的 SYNCSERVER_DIR 设置为指向 SYNCJ
运行 TESTSYNC\module\buildbat
配置 SyncJ 服务器
要配置 SyncJ请按以下步骤进行
在 Derby 中创建叫做 syncjdb 的数据库步骤 的代码中描述了 JDBC 设置这些设置假设 DERBY 中有一个叫做 syncjdb 的数据库用户名为 syncj口令为 syncj
用 Derby 附带的 IJ 工具创建并设置这个数据库(有关 Derby 工具的信息请参阅 参考资料)
设置 the properties in SYNCJ\installproperties 中的属性如下所示(用 JDBC 设置中的实际路径代替 DERBY)
dbms=derby
jdbcclasspath=DERBY/lib/dbjccjar;DERBY/lib/dbjcc_license_cjar;
jdbcdriver=comibmdbjccDBDriver
jdbcurl=jdbc:derby:net://localhost:/DERBY/syncjdb
jdbcuser=syncj
jdbcpassword=syncj
modulestoinstall=foundationpditestsync
设置 Derby 数据库
执行 DERBY\frameworks\NetworkServer\bin\startNetworkServerbat将 Derby 作为网络服务器来启动有关将 Derby 作为网络服务器启动的更多信息请参阅 Derby 的手册用 IJ 工具执行 TESTSYNC\create_table_serversql在 Derby 数据库中创建表 customer为 Tomcat 安装 SyncJ 服务器和示例模块要为 Tomcat 服务器安装 SyncJ 服务器并设置 SyncJ 数据库需要完成以下步骤
从 SYNCJ 中运行以下命令SYNCJ\bin\installcmd tomcat当给出命令提示时按 Y 来重新构建 testsync 模块的数据库从 SYNCJ 中运行 SYNCJ\bin\syncjtomcatcmd然后启动 Tomcat 服务器请注意服务器端设置现在可以安装客户机了
客户端安装
需要在客户端安装数据库引擎 HSQLDB然后安装并配置示例代码设置客户机应用程序和数据库要设置客户机应用程序数据库请按下以步骤进行
下载并解压 HSQL 数据库本文中用 HSQLDB 作为 HSQL 数据库的安装目录将 HSQL 作为网络服务器启动它带有一个叫做 test 的数据库运行 TESTSYNC\create_table_clientsql 在 HSQL 数据库中创建类似的表(customer)将 HSQL JDBC 驱动程序 HSQLDB\lib\hsqldbjar 复制到 TESTSYNC\client\lib在 TESTSYNC\client\config\spds\sources\testsyncproperties 中设置客户机的 JDBC 属性如下所示
jdbcDriver=orghsqldbjdbcDriver
urlConnection=jdbc:hsqldb:hsql://localhost/test
正确地设置用户名称和口令然后运行 TESTSYNC\client\buildbat 来构建客户端应用程序运行客户机应用程序向 Derby 数据库中的 customer 表中插入记录例如
insert into customer (userid password cl_op_type clo_op_time)
values (user pass N CURRENT_TIMESTAMP);
向 HSQL 数据库中的 customer 表中插入记录(请确保 userid 的值与 customer 中记录的值不同)例如
insert into customer (userid password cl_op_type clo_op_time)
values (user pass N CURTIME());
运行 TESTSYNC\client\output\testsyncbatcustomer 表现在应当包含刚才插入 customer 表中的记录而 customer 表应当包含来自 customer 表的记录
结束语
在本文中我们讨论了在设计通用数据库复制解决方案时涉及的一些重要概念和问题在设计复杂的分布式应用程序时资源占用少的嵌入式 Java 数据库的可用为您提供了一个很好的选择同时它还允许使用异构数据库对于复制过程和相关问题有很好理解有助于我们改进这类系统的设计我们鼓励您扩展这个示例以便用沖突解决策略来处理双向复制并使用记录更改数据的自动记录