服务数据对象旨在简化和统一应用程序处理数据的方式。使用服务数据对象,应用程序编程人员可以从异构数据源以统一方式访问和操作数据,其中包括关系数据库、XML 数据源、Web 服务和其他此类企业信息系统。
服务数据对象基于断开连接的数据图表。数据图表是数据对象的集合。在断开连接的数据图表架构中,客户机从数据源检索数据图表、更改数据图表,然后将这些数据图表更新应用于数据源。
将应用程序连接到数据源的任务是通过数据访问服务 (Data Access Service,DAS) 执行的(参见图 1)。客户机应用程序可以查询 DAS 并得到数据图表作为响应,修改数据图表并向 DAS 发送更新的数据图表,以便将这些更改应用到原始数据源中。客户机还可以使用 DAS 从一个数据源读取数据,并将其写入另一个数据源,例如,读取 XML RSS 信息包,并将结果写入关系数据库。此 SDO/DAS 架构原则上允许应用程序处理数据图表和数据对象。
图 1. DAS 的角色
SDO 的 PHP 实现涉及动态和弱型态语言的映射。结果是通过压缩许多特定于类型的 getter/setter,大大简化了 API。除此之外,SDO 还利用 PHP 的像处理数组那样处理对象的能力来实现对象,包括实现对集成的支持,声明测试和复位。结果形成一个使用简单的直观界面表现的功能强大的数据对象技术。
SDO 的核心概念是通过 SDO 模式和少量的接口定义的,这些接口用于实现与受该模式管理的实例数据进行的交互。图 2 显示了这些概念的一个 UML 类图表。现在我们将花一些时间了解一下不同元素的角色。
图 2. SDO 模式和接口
类和属性:在每个 SDO 实例的中心都有一个模式,用于定义所允许的数据对象结构。您可以将其想像为数据对象的蓝图。它包含的概念有父子数据对象关系、二元关系、数据对象上允许的属性、默认值,等等。SDO 模式是用术语类型 和属性 来描述的。类型可以是基元,如字符串(SDO 称它们为“数据类型”,并定义了一个映射到 PHP 类型的集合)或复杂 类型来代表序列 或地址(SDO 称它们为数据对象类型)。数据对象类型包含属性。每个属性都具有一个类型,这个类型可以是数据类型,或者数据对象类型。
此“类型”和“属性”模式允许数据对象指出哪种 SDO 是指数据图表。数据图表本质上是一个树结构的数据对象,可以通过它们的包容引用(您可以将它们想像为父子关系的容器或集合)以及指向数据图表中数据对象的非包容引用(它们不是集合关系,因此可以指向树中的任何其他数据对象)进行导航。
我们使用 Person 数据对象的例子来说明“类型”和“属性”这两个重要概念。下图显示的例子是一个 Person SDO 实例(左侧)及其应的模式(右侧)。Person SDO 实例的名称由名为“Person”的类型定义。定义的 Person 类型有两个属性,名称分别为“name”和“age”。这两个属性的类型是 SDO 数据类型的“字符串”和“整形”;在左侧,我们可以看到 Person 实例已将这两个属性的值分别设置为“Fred Fish”和 35。
图 3. Person SDO 实例和模式示例
除了提及的属性外,类型还具有所谓的是否为开放(例如,支持类型中未定义的其他实例属性)、序列(属性中的保存顺序)或抽象(由另一 SDO 类型扩展的抽象基本类型)的属性。属性还具有描述二元关系(例如,代表公司各部门的多值属性)、任何默认值之类内容的特性,无论该属性是否为只读。并不是所有这些概念在 SDO 的 PHP 实现中都受支持。SDO for PHP 项目随附的文档描述了各种功能的状态。所有这些概念都在 Java SDO 规范中进行了详细说明(请参阅参考资料)。
DataObject:处理数据对象的核心接口是 DataObject(这并不足为奇)。它支持处理数据结构(例如,设置和获取属性、创建子结构、通过增大的 XPath 进行属性查询以及结构导航)时所需的所有功能。
对于上述示例,我们可以使用 DataObject 接口获取年龄属性值 35,然后使用它将年龄更新为 36。DataObject 接口的用法在联系人场景中进行了详细的描述。
序列:序列接口用于需要在跨数据对象的属性进行排序时操纵数据对象(数据对象被称为一个排序类型)。当处理 XML 数据并且属性值的顺序特别重要时此属性特别有用,但对每个实例又各不相同,因此未被模式明确定义(例如,对于混合的 XML 内容)。
正如简介中所述,SDO 依赖于 DASes 的存在。DAS 的作用是从数据源检索数据以及向其中写入数据。在使用 DAS 时,客户机与 SDO 交互,因此与任何特定于数据源的数据表示相隔离。
DAS 还可以充当数据对象的工厂,创建符合某个预定义的数据源架构(例如,一个数据库或 XML 架构)的新实例。
两个 DAS 实现是作为 SDO for PHP 项目的一部分提供的。它们是关系型数据源访问服务(关系型 DAS),用于与 XML 文件或 XML/HTTP 源交互的 XML DAS 和用于访问关系数据源,并由 PHP 数据对象 (PDO) 实施。
考虑到使用 SDO 的原因有许多种,下面只列出了其中的一些主要原因。
减少数据库开销:SDO 的核心是支持断开连接的工作。数据对象可以自动记录它们的更改历史,然后,在将这些更改应用到企业信息系统时,DAS 将使用这些更改来检测冲突。
此技术通常称为开放式并发 (optimistic concurrency) 或 开放式脱机锁定 (optimistic offline locking )(“企业应用程序体系结构的模式 ”一文中对此进行了描述,这篇文章的作者是 Martin Fowler)。它最适合于磁盘冲突少的情形,磁盘冲突较少可能是由于编辑较少,或者编辑由一个外部进程控制,该进程可降低多人同时处理同一数据的可能性。
除了磁盘冲突少外,如果还存在高编辑延迟(签出来进行编辑与提交编辑之间的有效时间较长),或者以使数据库连接和锁定较难管理的方式传递数据(例如,在面向服务的应用程序体系结构中),这种优势就会更大。
使用此技术的主要好处是消除了在企业信息系统中,当某个用户或应用程序处理数据时,需要由应用程序来保持连接和锁定。
有趣的是,在 SDO 体系结构中,没有存在任何东西可以排除对使用封闭式并发 (pessimistic concurrency) 模式的 DASes 的创建。
数据的单一 API:除了开放式并发的支持外,在处理多个异构数据源时,您会认识到使用 SDO 的另一个主要好处。SDO 提供了用于操纵数据的独立于数据的原始数据源的单一 API。
除了预期的数据源操作支持之外,SDO 还提供了基于类似 XPath 的表达式(包括查询)设置和检索 SDO 内容的能力。这消除了客户机的压力,不必去导航数据源,并根据实例数据来确定子结构。例如,我们可以选择扩展 Person 示例,使之包括一个新的数据对象类型,该类型包含一个 Person 数据对象的集合。要按名称而不使用 XPath 来确定个别对象,则需要重复所有 Person 对象并测试名称属性,直到发现匹配的对象。使用 XPath 执行此工作,只需要一个简单的调用,指定要匹配的属性名和值即可。
结构的知识:我们已经了解到,SDO 携带数据结构表现(即模式)的内部知识。该知识用于确保对实例数据的创建和修改符合数据对象的结构和类型规则。
数据功能(如 SimpleXML 和 PDO)不使用这种方法,因此,在创建和验证数据时,必须将此职责指派给其他技术。结果,构建于 SDO 之上的 SimpleXML 和 PDO 的好处是省去了开发人员指定模式的必要。
拥有模式的其他好处是可以在运行时对其进行自省。例如,这可以让开发人员编写灵活的用户界面,以适应在运行时数据结构(SDO 架构)的更改。SDO 模式自省在 PHP 实现中没有完全启用,但我们预期这一现象会随时间而发生变化。
PDO(不要与 SDO 混淆)旨在为多数关系数据库 API 中的通用功能提供一个一致的 API。这大大简化了 Web 应用程序(通过封装差别,在一个通用的 API 下支持不同的数据库供应商)的创建。PDO 提供了一个简单的对象结果视图,但并不尝试标准化这些结果(结果集的一行对应于一个对象,而不论该结果是否代表多个表)。PDO 的易用性使之在直接处理数据库时很自然地成为了首选方法,就因为这一原因,SDO 提供的关系型 DAS 实现也选择了此技术。
刚才已提到,SDO 的重点是为异构数据源中数据提供一个灵活的数据对象表示,并为开放式并发提供内置支持。我们还介绍了如何让 SDO 使用“结构知识”为数据的完整生命周期(包括创建和验证)提供单一的 API。如果这些功能对您的应用程序较为重要,那么 SDO 也许是您较合适的选择,使用对 PDO 实施的关系型 DAS 提供关系型数据源支持。
SimpleXML 提供了一个处理 XML 实例文档的简单方法。通过一个简单的 API 可以加载文档,并能够导航和操作。界面显示了 XML 的一些细节(例如,元素和属性之间的语法区别)。
在解析和处理实例文档时,SimpleXML 是一个好的技术选择。然而,如果需要一些重要的操作,那么让该技术了解适用于该文档的模式非常重要,在此情况下,SDO 可能是更为合适的选择。
现在您应当已经较好地理解了 SDO 的主要概念。为了进一步明确,我们将用简单的场景进行说明。
以下各节提供了 SDO for PHP 功能的概述,在个人联系人环境示例中进行了描述。此示例演示了 SDO 的下列属性:
- 断开的工作(开放式并发)
- SDO 导航和操作
- DAS 的角色
提供的代码片段是为帮助解释概念和开发要求。然而,这不是我们描述完整工作示例的目的。我们期望将来的文章能够包括工作示例,并详细说明关系数据库和 XML DASes 的用法。
在此场景中,编写了一个联系人 Web 应用程序来支持对联系人信息的管理。联系人信息存储在关系数据库中,该数据库包括下面两个表:
表 1. “联系人”表定义
| 列 | 类型 | 示例 |
| 短名称(主键) | 字符串 | "Charlie" |
| 全名称 | 字符串 | "Charles Babbage" |
表 2. “地址”表定义
| 栏 | 类型 | 示例 |
| 地址(自动生成的主键) | 整形 | 1 |
| 短名称(外键) | 字符串 | "Charlie" |
| addressline1 | 字符串 | "Analytical House" |
| addressline2 | 字符串 | "1 Engine Close" |
| 城市 | 字符串 | "Walworth Road" |
| 国家 | 字符串 | "London" |
| 邮政编码 | 字符串 | "XX11 1ZZ" |
| 电话 | 字符串 | "555-555-5555" |
为了说明 SDO 的用法,我们选择了修改联系人做为用法案例。修改联系人的主要步骤如下:
- 从数据库中检索要修改的联系人。
- 对联系人进行修改。
- 将修改应用到数据库。
下面对这些步骤进行了更为详细的介绍。
注意:我们已经提到,DAS API 没有被指定为 SDO 的一部分,因为我们指的是 SDO 规范,因此,任何示例代码有必要特定于某一特殊实现。下面显示的已创建代码片段用来匹配 SDO for PHP 提供的关系型 DAS 的 API。
用户看到的第一页是联系人管理 main.php 页。其中有一个输入字段用于输入要编辑的联系人的短名称,还提供了一个 Edit 按钮来提交请求。
图 4. 联系人管理主页
输入一个短名称并单击 Edit 转到 edit.php 页,将指定的短名称传递到 $_POST 数组中。edit.php 页包含以下主要步骤:
- 获取输入的短名称。
- 创建一个关系型 DAS 实例。
- 执行查询以检索联系人 SDO。
- 在编辑表单中填写联系人详细信息。
- 将联系人 SDO 存储在会话中。
下面将对这些步骤逐一进行说明。
1. 获取短名称:欢迎页表单配置导致短名称放在 $_POST['shortname'] 中。
// get the shortname from posted variables $shortname = $_POST['shortname']; |
2. 创建一个关系型 DAS 实例:创建关系型 DAS 的一个重要方面是描述它应使用的数据库架构。关系型 DAS 采用此架构并使用它定义可以创建的服务数据对象的模式。此信息通常是其他关系型 DAS 实例所需的,因此,它是一个候选信息,用于填入单独的脚本然后包括其中。
清单 1. 描述数据库架构
// Describe the structure of the contact table
$contact_table = array(
'name' => 'contact',
'columns' => array('shortname', 'fullname', 'telephone'),
'PK' => 'shortname'
);
// Describe the structure of the address table
$address_table = array (
'name' => 'address',
'columns' => array('id', 'contact_id', 'addressline1', 'addressline2',
'city', 'state', 'zip'),
'PK' => 'id',
'FK' => array ('from' => 'contact_id', 'to' => 'contact')
);
$table_metadata = array($contact_table, $address_table);
// Describe the parent-child relationship. This is information required
// by the Relational DAS to help map from the relational database representation to
// the data graph representation of SDO.
$address_reference = array('parent'
=> 'contact', 'child' => 'address');
|
注意:关系型 DAS 假定所有包容关系都是一对多的二元关系。因此在此示例中,联系人可以包含零个或更多的地址 DataObject 实例。
定义了模式之后,我们现在可以创建一个关系型 DAS 的实例。
清单 2. 创建关系型 DAS 实例
// Create the Relational Data Access Service telling it the database // schema, that table should be considered the root of the graph, // and finally the additional information for the object model. $das = new SDO_RDAS($table_metadata, 'contact', $address_reference); |
3. 执行查询:现在我们可以使用关系型 DAS 来检索联系人信息。
清单 3. 使用关系型 DAS 检索联系人信息
//connect to the database. This connection will be released when the
// $dbh variable is cleaned up.
$dbh = new PDO('mysql:dbname=contactdb;host=localhost', DB_USER, DB_PASSWORD);
// construct the SQL query for contact retrieval
$stmt = "select * from contact, address where contact.shortname=$shortname and
contact.shortname=address.contact_id";
// execute the query to retrieve the contact
$contact = $das-executeQuery($dbh, $stmt);
|
结果 $contact SDO 显示如下。其中显示了数据对象、这些对象的属性(属性检索显示在方括号中,后跟属性名)以及属性值。刚才已经提到,联系人中地址包容的二元关系由关系型 DAS 假定为一对多的关系。在下图中,“[0] DataObject”标记用于表示地址 DataObjects 列表中的第一个条目。
图 5. 联系人 SDO 实例
4. 填写编辑表单:对于联系人 SDO,我们可以填写表单,以便用户能够编辑数据。
清单 4. 填写编辑表单
// Create and populate the form with the contact details <form action= ... method="POST"> <input type="text" name="fullname" value="$contact->fullname"> ... <input type="text" "name="addressline1"" value=" $contact->address[0]->addressline1"> ... </form> |
5. 在会话中存储数据对象:由于我们已从数据库断开连接,因此需要将联系人数据对象存储在会话中,以便将它用于下一页。
// store the contact data object in the session $_SESSION['contact_sdo'] = $contact; |
前面的部分简要介绍了访问 SDO 的属性(参见步骤 4 “填写编辑表单”中的代码)。除了访问原始属性外,多数 SDO 应用程序还需要上下导航父子数据对象关系(例如,在联系人和地址之间导航)。有些应用程序还需要查询功能,以标识数据图表的某些部分。
下面的代码片段简要概述了导航联系人 SDO 数据图表的方式。
在步骤 4 中我们可以看到,SDO 使用对象属性来支持属性访问:
// get the fullname using the object property $fullname = $contact->fullname; |
我们还可以使用属性检索来访问全名称(数据对象模式定义的位置,如图 4 中的方括号中所示):
// get the second contact property (fullname) $fullname = $contact[1]; |
我们可以使用相同的语法访问多值子数据对象属性(例如地址):
清单 5. 访问多值子数据对象属性
// get the list of address data objects via the object property $addresses = $contact->address; // get the list of address data objects via the property index $addresses = $contact[2]; |
我们可以使用数组语法访问多值属性的个别元素,例如第一个地址:
// get the first address from a list of address data objects $address1 = $contact->address[0]; |
我们还可以直接引用子数据对象属性中的属性,例如第一个地址中的 zip 代码:
清单 6. 子数据对象属性中的引用属性
// access the zip code from the first address via the object properties $zip = $contact->address[0]->zip; // access the zip code via the property indices. // access the zip code via the property indices. // Note: this style is not recommended since it leads to virtually // unserviceable code. The XPath-style (described later) or defining // constants lead to much more readable code. $zip = $contact[2][0][5]; |
我们还可以重复数据对象的属性:
清单 7. 重复数据对象的属性
// Iterate over the properties of the first address
// $name is assigned each property name (e.g. "id", "addressline1", ...)
// $value is assigned each property value (e.g. 1, "Analytical House", ...)
foreach ($contact->address[0] as $name => $value) {
echo "$name $value";
}
|
最后,我们可以使用类似 XPath 的支持(作为属性名称的最简单的表单)来访问这些属性:
清单 8. 使用类似 XPath 的支持访问属性
// use property names (XPath) to access the zip property $zip = $contact['address'][0]['zip']; // use single XPath expression with array index notation to access the zip property // Note: XPath array indices start at 1. $zip = $contact['address[1]/zip']; // use single XPath expression with dotted index notation to access the zip property // Note: SDO dotted notation indices start at 0. $zip = $contact['address.0/zip']; |
XPath 还可以用于导航和查询数据对象。如果我们已在关系型 DAS 查询中检索到许多联系人,则可以从其第一个地址行标识个别联系人,例如:关系型 DAS 作为根数据对象的多值子属性返回多个结果,在该示例中我们已将其命名为 $root。
清单 9. 使用 XPath 导航和查询数据对象
// Get the address object that contains the addressline1 of "1 Engine Close" $address = $root["contact/address[addressline1=\"1 Engine Close\"]"]; // Get the contact with the matching address. GetContainer() navigates to the // parent of a data object, in this case the contact SDO. $contact = $address->getContainer(); |
下面显示了一个包含联系人编辑页 edit.php 的简单示例,其中联系人有一个单地址:
图 6. 联系人编辑页
该页允许用户修改个别属性值。在锁定 Update 按钮时,所有值将放置在 $_POST 数组中,无论这些枝是否已修改,并且应用程序将转换到 confirm.php 页。确认页执行下面的主要步骤:
- 从会话中检索联系人 SDO。
- 更新联系人 SDO。
- 创建关系型 DAS 实例。
- 将更改回写到数据库。
- 通知用户结果。
下面将分别对其中每个步骤进行介绍。
1. 从会话中检索联系人 SDO:执行编辑页的最后一步是将联系人 SDO 放入会话。现在我们检索此联系人以便进行更新。
// retrieve the contact from the session $contact = $_SESSION['contact_sdo']; |
2. 更新联系人:现在已经有了联系人,我们可以着手对编辑页传递的内容进行更新。操作方式是将传递的值和原来的值进行比较,如果存在不同,则在联系人上设置传递的值。这样做是为了避免设置不必要的值并导致 SDO 在更改概要中记录一个更改(仍然保留已更改的数据对象的旧值)。如果 SDO 实现能够代替我们执行此项测试则较为理想。
清单 10. 更新联系人
// update the fullname if changed
if ($contact->fullname != $_POST['fullname']) {
$contact->fullname = $_POST['fullname'];
}
... |
3. 创建关系型 DAS:下一步是创建关系型 DAS,用于将更新写入数据库。此代码与检索中使用的代码相同,并且上面已经提到过,它已被适当地放置在单独的脚本(例如“contact_model.inc.php”)中。
// initialize the Relational Data Access Service
require_once('contact_model.inc.php');
|
4. 将更改写回数据库:下一步是将更改应用回数据库。下面的调用显示了如何对关系型 DAS 实现这一点。不需要为更新指定 SQL 语句,原因是关系型 DAS 可以从模式和联系人数据对象的更改概要中派生它。
// apply the changes back to the database $das->applyChanges($dbh, $contact); |
applyChanges() 调用非常简单。它在封装中执行下列操作:
- 对 SDO 更新进行排序,以确保提供了正确的值(例如,在更新之前创建)。
- 生成 SQL
INSERT、UPDATE和DELETE语句来应用更改。UPDATE和DELETE语句用数据的原始值进行限定,这样,如果数据库中的数据同时进行了更改,则会检测到此更改。 - 执行 SQL 语句 —— 如果未能执行任何 SQL 语句,则表明发生了冲突,并且关系型 DAS 将回滚所有更改并抛出异常。如果所有语句都成功执行,则将所有更改提交到数据库。然后客户机应用程序可以继续处理数据对象,进行更多更改,并应用更改或撤消更改。
5. 通知用户结果:最后一项任务是通知用户结果。如果关系型 DAS 未检测到冲突,而且成功完成更新,则一切均为正常。
图 7. 确认页
上一节大致介绍了访问和设置 SDO 属性(参见步骤 2“更新联系人”中的代码)。除了设置原始属性外,多数 SDO 应用程序还要求创建子数据对象和删除部分数据结构。下面的代码片段给出了希望在联系人 SDO 上执行的其他类型修改的简要概述。
针对获取个别属性而介绍的技术还适用于以下设置:
清单 11. 设置个别属性
// set the fullname via the object property $contact->fullname = 'Alan Turing'; // set the fullname via the property index $contact[1] = 'Alan Turing'; // set the fullname via the property name (XPath) $contact['fullname'] = 'Alan Turing'; |
我们可以创建子数据对象。例如,编辑用户接口允许将新地址添加到联系人中。当传递新地址详细信息时,我们可以执行以下操作:
清单 12. 创建子数据对象
// create a child address data object
$address = $contact->createDataObject('address');
// set the address's addressline1 property from the posted value
$address->addressline1 = $_POST['addressline1'];
|
注意:此子数据对象会自动插入图表,而且 $address 仅是图表中该位置的引用。因此,如果这是添加的第一个地址,下面将在联系人地址上同时设置 ZIP 代码。
清单 13. 设置 ZIP 代码
// set the address 's zip $address->zip = 'XY11 2ZZ'; // set the addresses zip via the contact data object $contact->address[0]->zip = 'XY11 2ZZ'; |
我们可以测试和取消设置联系人的个别实例属性。例如,如果用户清除了接口中的字符串,那么我们可以使用它来表示取消设置:
清单 14. 测试和取消设置个别实例属性
// if the fullname value was cleared on the edit page and the fullname
// was previously set then unset the fullname property
if (empty($_POST['fullname']) && isset($contact->fullname)) {
unset($contact->fullname);
}
|
最后,我们可能还希望能够删除编辑页中的联系人或联系人的地址,这一点还可以通过取消设置来实现:
清单 15. 启用联系人的删除
// test and unset the first address
if (isset($contact->address[0])) {
unset($contact->address[0]);
}
|
在 PHP 中,SDO 可以添加一些有趣的功能来处理数据,同时可以保持 PHP 开发人员所希望的简单易用的界面。SDO 可以表示来自异构数据源的复杂的数据结构,同时允许通过一个类似于 SimpleXML 和 PDO 的单一 API 进行操作。在 SDO 中构建了开放式并发支持,允许处理断开连接的数据,而无需要求应用程序实施更改跟踪和冲突检测。
本文简要介绍了 SDO 的一些功能,但还有许多功能本文尚未涉及。希望以后的文章中能够介绍以下这些主题,其中包括
- 数据对象的不同的类(或类型):有序类、开放类和抽象类。
- 关系型 DAS 的详细信息。
- XML DAS 的详细信息。
- 使用 SDO 服务提供商接口实现 DAS。
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
- “服务数据对象简介”(developerWorks,2004 年 9 月)提供了新一代数据编程的介绍。
-
IBM 和 BEA 协作共同制定编程模式和用于 Java 2 企业版 (J2EE) 应用程序服务器的 API 的规范,为编程人员提供一个用于构建便携式服务器应用程序的简单而强大的方法。请在以下位置该内容:“服务数据对象、WorkManager 和计时器”(developerWorks,2005 年 6 月)。
- “将 PHP 连接到 Apache Derby”介绍了如何在 Windows® 上安装和配置 PHP。
-
第一个特定于 PHP 的 SDO 资源可以在 PHP.net 的数据包位置中找到。SDO for PHP 项目:SDO for PHP 项目作为 PECL 的扩展提供。
-
第二个特定于 PHP 的 SDO 参考资料可以在 PHP.net 网站的文档部分找到:SDO for PHP 文档:PECL 扩展在 PHP 文档的“函数引用”一节中进行了介绍。
-
请访问 developerWorks 的开放源码专区,了解范围更广的 how-to 信息、工具和项目更新,从而帮助您使用开放源码技术进行开发并将他们用于 IBM 的产品中。
获得产品和技术
-
使用 IBM 测试软件创新您的下一个开放源码开发项目,可以通过下载或 DVD 获得。
讨论
- 通过参与 developerWorks blogs 加入 developerWorks 社区。

Graham Charters 在英国 Hursley 的 IBM 开发实验室工作。他曾经从事过 WebSphere® Application Server 的开发,负责 WebSphere Business Integration 和 Adapters 的架构。他目前对开放源代码技术颇感兴趣,比如 LAMP(Linux®、Apache、MySQL、PHP/Perl/Python)和 IBM WebSphere 平台的关系。Graham 拥有曼彻斯特大学的计算机科学、数值分析和机器视觉学位。

Matthew Peters 在英国 Hursley 的 IBM 开发实验室工作。他曾经参与开发了 IBM CICS® 和 MQSeries® 产品,并曾与科学技术计算和大型并行处理领域的业务伙伴有过多年合作。最近他在从事 IBM JVM 的垃圾收集器开发。Matthew 拥有剑桥大学女王学院的数学学位和牛津大学的软件工程博士学位。

