简介:作者 Thomas Myer 向资深 PHP 开发人员讲述如何把 CouchDB 添加到他们的技术工具箱中。
如果您是位典型的 PHP 开发人员,就不难通过以往的项目得到这样一个结论:在多数(如果不是全部)情况下,为了进行动态数据处理,您都会让 PHP 与数据库后端进行对话;而在这些实例中,99% 的情况下使用的都是 MySQL。
如今,使用关系型数据库无可厚非。如果所处理的数据结构复杂,并具有多种关系,那么这么做是很合理的。您可以顺利地(或是不太顺利地,取决于您对 SQL 的熟悉程度)进行对模式、数据关系、表等等的处理。
不过,您所从事的项目有时也会让您不经意间心生疑问:“为什么我要做所有这些工作?” 您所从事的这个项目包含了一些简单的或难以预测的数据 — 在不同的日子获得的数据字段可能不同甚至事务之间的数据字段都不尽相同。若是创建一个模式来预测将会出现什么数据字段,结果很可能会得到内含大量空字段的表或大量的映射表。
对于这些项目,您需要采用一种不同的方式 — 不涉及关系型数据库。在这些情况下,您需要的是一个基于文档的、没有模式的、具有扁平地址空间的特别数据库。简言之,您需要 Apache CouchDB。
CouchDB 是(根据 Apache CouchDB 网站):
这意味着,您可以创建一个能够接受 JSON 文档的 CouchDB 数据库。每个文档均有一个惟一的修订 ID 和自身结构,而且所有文档均存储于同一个扁平的集合内。例如,假设您设置了一个简历集。第一个简历具有的字段包括:名、姓、电话号码、电子邮件地址、Twitter 帐户、特长以及详细的工作经历。而第二个简历则只有名、姓、电子邮件地址以及一个简短的工作经历。这种差异足以使关系型数据库变得非常不适合,但对于 CouchDB,这点差异稀松平常。
简言之,一个 CouchDB 文档就是一个由多个命名字段组成的对象。这些字段的值可以是字符串、布尔值、数字、日期、顺序列表或关联映射。清单 1 展示了一个示例简历文档。
{ "Firstname": "Tom" "Lastname": "Myer" "Twitter": "@myerman" "Email": "[email protected]" "Skills": ["php","couchdb","xml","json"] "Work History": .... } |
到目前为止,如果您习惯了使用 JSON,那么不会觉得有太大出入。即便您不习惯,您仍然可以将此文档对应成您所熟悉的东西,比如一个 PHP 数组。实际上,您可以将这些内置的 JSON encode/decode 函数用于 CouchDB,或者您也可以选择一种更为面向对象的方式。
为了从一个集合查询信息,您可以通过 RESTful JSON API 使用各种便利的查询方法。使用 JSON 简化了很多问题。还有一点,作为一个熟悉 JavaScript、Ajax 和 JSON 的 Web 开发人员,您无需掌握 SQL 也能完成任务。
在继续之前,最好暂停一下,先来着重强调几点。CouchDB 不是一个关系型数据库。这一点我可能早就说过了,但是它需要反复强调。不要试图以关系型数据库的方式使用 CouchDB,比如插入 ID 字段来帮助理清文档间的关系。与创建关系不同,您需要将想要的内容塞入到文档,然后继续。
此外,CouchDB 亦不是一个面向对象的数据库。它不是什么本地对象、持久数据层供您用作面向对象结构的基础。千万不要这么认为。
如果您使用的是 Mac OS X,CouchDB 的安装过程十分简单:
sudo port install couchdb
。 sudo port upgrade couchdb
。 sudo launchctl load -w /opt/local/Library/LaunchDaemons/org.apache.couchdb.plist |
为了查看 CouchDB 的实际效果,在您的浏览器内键入 http://127.0.0.1:5984/_utils/index.html。Futon 实用工具就会出现,如图 1 所示。
在 Windows® 系统上,过程将会有些复杂,因为您将需要先安装 Microsoft® C 编译器 Cygwin、其他的一些前提条件(比如 cURL、ICU 和 SeaMonkey)、下载并安装 Erlang 和 Couch 源代码、根据 README 文件对其进行配置,然后才能进行一次完整的安装。这一过程在 CouchDB wiki(参见 参考资料)内有详细的描述。您还将能够找到针对 Linux®、Berkeley Software Distribution (BSD) 和其他环境的指导。
在进入 PHP 之前,最好是先对 CouchDB API 有些了解,此 API 可通过 HTTP GET
和 PUT
请求访问并返回 JSON 格式的数据。不管您使用的是何种语言 — PHP、Microsoft Active Server Pages (ASP)、Ruby、Python 或更为简单的 jQuery Ajax 函数,这种设置都会使从 Web 应用程序存储和检索数据得到简化。
本节展示如何使用这个 cURL 命令行工具向 CouchDB 发出 GET
、POST
、PUT
和 DELETE
请求。掌握了这个 API 之后,就可以借助一个特别的 PHP 包装器简化开发任务。
您首先需要运行的(仍然是从 Terminal 窗口)是这个命令:curl http://127.0.0.1:5984/
。随后,应该会得到类似于 {"couchdb":"Welcome","version":"0.10.0"}
的一个响应。这只是为了告诉您 CouchDB 已经启动并运行以及所使用的是何版本。如果您没有看到这个消息,那么就请重新进行安装和配置直至 CouchDB 启动并运行。
现在,尝试列出在 CouchDB 内设置的所有集合。运行 curl -X GET http://127.0.0.1:5984/_all_dbs
。
如果 CouchDB 是初次安装,应该会看到响应 []
,这意味着没有任何集合或数据库(方括号代表的是一个空的 JavaScript 数组)。请注意在这个 cURL 命令中,使用了 -X
选项来显式指定一个 GET
操作。
现在,让我们通过创建一个数据库来解决该问题:
curl -X PUT http://127.0.0.1:5984/songs |
在运行上述命令后,会得到响应 {"ok":true}
。现在您知道您可以查看 ok
属性来确认成功与否。再次运行 curl -X GET http://127.0.0.1:5984/_all_dbs
,结果会得到一个非空数组:["songs"]
。并且,您的 CouchDB 实例内具有这样一个数据库:songs。
现在尝试创建另一个名为 songs 的数据库。如果您再次运行 curl -X PUT http://127.0.0.1:5984/songs
,将会获得一个如下所示的错误消息:
{"error":"file_exists","reason":"The database could not be created, the file already exists."} |
所以您可以很容易地查看 error
属性来确认问题发生与否。
创建第二个名为 foobar 的数据库:
curl -X PUT http://127.0.0.1:5984/foobar |
如果运行 curl -X GET http://127.0.0.1:5984/_all_dbs
,结果会获得响应 ["songs","foobar"]
。为了去掉第二个数据库,可以向它传递一个 DELETE
调用:
curl -X DELETE http://127.0.0.1:5984/foobar |
运行 curl -X GET http://127.0.0.1:5984/_all_dbs
表示您已经回至 ["songs"]
。
现在继续,在 songs 数据库内创建一些文档。毋庸置疑,您想要在这个数据库内存储一些歌曲,这些歌曲具有曲名、艺人名称和专辑名称字段。要创建一个文档,遵循如下这个模式:
curl -X PUT http://127.0.0.1:5984/songs/*id* -d '{ *json_data* }' |
注意到先是调用数据库的名称,随后是 ID(要求 ID 不仅要在这个 CouchDB 实例中惟一,而且还要尽量在所有实例中惟一),再后来是 JSON 数据。
如何获得惟一 ID?可以使用一个 UUID(或一个 GUID)作为惟一 ID,或者也可以创建某种综合了各种小块数据的自然键(比如,歌曲名中用下划线代替空格,再加上时间戳),或者是让 CouchDB 为您创建一个惟一 ID (这个过程很慢)。上述方式都不错,只是不要像在 MySQL 环境内那样使用自动增量的值。
现在,向您的数据库内输入一首歌曲:
curl -X PUT http://localhost:5984/songs/whatever_you_like -d / '{"title":"Whatever You Like", "artist":"T.I.","album":"Paper Trail"}' {"ok":true,"id":"whatever_you_like","rev":"1-1d915e4c209a2e47e5cf05594f9f951b"} |
请注意我对这个惟一 ID 采用了一个十分简单的方式(使用了一个简化了的歌曲名称,用下划线代替了空格)。这种简单的方式对于目前的需要还能满足。幸运的是,在 PHP 内将要使用的包装器会帮助您创建更好的 ID。也请注意我立即收到了一个 “ok” 响应,并且其中的文档 ID 和 rev
属性还告知了所设置的修订版本。
要查看刚刚添加的这个文档,可以尝试:
curl -X GET http://localhost:5984/songs/whatever_you_like {"_id":"whatever_you_like","_rev":"1-1d915e4c209a2e47e5cf05594f9f951b", "title":"Whatever You Like", "artist":"T.I.", "album":"Paper Trail"} |
如果您一直在 Futon 内尝试,应该能够单击这个歌曲数据库名并在文档列表内看到一个 whatever_you_like
项。单击该链接会显示所感兴趣的这个文档的详细信息,如图 2 所示。
您逐渐发觉 — 用 JSON 做出 RESTful 请求后就会有事情发生。
现在,所有这些看上去都很好,但是如果您是一名 PHP 开发人员,可能会疑惑如何将这些综合在一起形成自己熟悉的东西呢。下一节会向您介绍面向 CouchDB 的 PHP 包装器。
对于下一个步骤,您需要从 Github 下载 PHP-on-Couch(参见 参考资料)。将解压缩了的 /lib 文件夹内容放入您的开发区域。在设置好工作区域后,创建一个简单的 PHP 应用程序来与已经设置好的这个 CouchDB 数据库(您的歌曲集)对话。创建一个新文件,然后将其命名为 index.php。并在其内放入清单 2 内的代码。
<?php $couch_dsn = "http://localhost:5984/"; $couch_db = "songs"; require_once "./lib/couch.php"; require_once "./lib/couchClient.php"; require_once "./lib/couchDocument.php"; $client = new couchClient($couch_dsn,$couch_db); ?> |
上述代码充当的是到 CouchDB 的连接代码并且包含使用此数据库所需的所有相关类。接着列出与数据库相关的全部信息,如清单 3 所示。
try { $info = $client->getDatabaseInfos(); } catch (Exception $e) { echo "Error:".$e->getMessage()." (errcode=".$e->getCode().")/n"; exit(1); } print_r($info); |
得到的结果应该类似于清单 4。
stdClass Object ( [db_name] => songs [doc_count] => 2 [doc_del_count] => 0 [update_seq] => 2 [purge_seq] => 0 [compact_running] => [disk_size] => 8281 [instance_start_time] => 1266082749089965 [disk_format_version] => 4 ) |
接下来,从歌曲数据库中检索一个文档。清单 5 给出了所需代码。
try { $doc = $client->getDoc('whatever_you_like'); } catch (Exception $e) { if ( $e->code() == 404 ) { echo "Document not found/n"; } else { echo "Error: ".$e->getMessage()." (errcode=".$e->getCode().")/n"; } exit(1); } print_r($doc); |
清单 6 给出了响应。
stdClass Object ( [_id] => whatever_you_like [_rev] => 1-1d915e4c209a2e47e5cf05594f9f951b [title] => Whatever You Like [artist] => T.I. [album] => Paper Trail ) |
很不错,但是如何对一个文档进行更新呢?可以做的更新有两种:更改现有字段值;添加新字段和新值。对于后者,可以使用箭头表示法(比如 $doc->new_field
),然后通过 storeDoc()
保存更改。清单 7 显示了更新一个文档所需的代码。
$doc->genre = 'hip-hop'; $doc->year = 2008; try { $response = $client->storeDoc($doc); } catch (Exception $e) { echo "Error: ".$e->getMessage()." (errcode=".$e->getCode().")/n"; exit(1); } |
运行此代码,然后就可以检索这个文档 ID 并获得清单 8 内所示的结果。
stdClass Object ( [_id] => whatever_you_like [_rev] => 2-12513a362693b300928aa45f82faed83 [title] => Whatever You Like [artist] => T.I. [album] => Paper Trail [genre] => hip-hop [year] => 2008 ) |
注意到 _rev
属性已经从之前的 1-whatever
增加为 2-whatever
。借此,就可以很容易地判断已经发生了更改。
那么,该如何在数据库内存储一个新文档呢?您可以实例化一个新对象并使用箭头表示法来填充文档内的字段。清单 9 显示了所需代码。
$song = new stdClass(); $song->_id = "in_the_meantime"; $song->title = "In the Meantime"; $song->album = "Resident Alien"; $song->artist = "Space Hog"; $song->genre = "Alternative"; $song->year = 1995; try { $response = $client->storeDoc($song); } catch (Exception $e) { echo "Error: ".$e->getMessage()." (errcode=".$e->getCode().")/n"; exit(1); } print_r($response); |
结果应该类似清单 10。
stdClass Object ( [ok] => 1 [id] => in_the_meantime [rev] => 1-d65b03a9fe2f3c8095b08883e7cd97df ) |
至此,您应该具备了开始使用 CouchDB 和 PHP 的足够信息。您也应该能够轻松创建您的基本更新表单并能在日后创建或更新数据库内的现有文档。PHP-on-Couch 包还为您提供了创建和删除数据库以及使用 CouchDB 视图等的其他方法。总之,本文有足够信息可以让您从开始就有一个很好的起点。
<!-- CMA ID: 486193 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->
学习
获得产品和技术
文章来源:http://www.ibm.com/developerworks/cn/opensource/os-php-couchdb/index.html