免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3422 | 回复: 1
打印 上一主题 下一主题

MySQL一派添“轻功”Drizzle+PHP抢先体验(zz) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-08-10 15:01 |只看该作者 |倒序浏览
Drizzle是从MySQL衍生出来的一个数据库服务器,相信只要你不是两耳不闻开源事,就应该已经对其有所了解了。Drizzle项目的宗旨是构建一个“更精练、更轻量、更快速”的MySQL版本,它的扩展性和易用性与MySQL相当,但为了提高性能和扩展性,它从原来的核心系统里移除了部分功能。

  虽然Drizzle现在还只是个比较新的项目,但是它已经吸引了很多开源开发者,他们非常乐意为Drizzle作测试,提供代码,并在自己的项目里使用它。这也正是本文的目的所在。接下来,我将带你体验Drizzle,向你展示如何编译和安装它,如何创建一个Drizzle数据库,以及如何用 PHP连接到这个数据库。下面就让我们开始吧。

  不同之处

  按照其官方网站上的说法,Drizzle是“一种为云和网络程序进行了特别优化的数据库,它是为在现代多CPU/多核架构上实现大规模并发而设计的。”它以GNU GPL v2许可证发布,项目带头人是MySQL的Brian Aker。

  虽然Drizzle是MySQL的一个分支,但它的目的并不是要取代MySQL;相反,它的目的是吸引那一部分既想要MySQL的可靠性,ACID兼容性和易用性,又不需要存储过程、触发和视图这些MySQL新功能的用户。

  在其它一些方面,Drizzle也有别于MySQL:

  ◆它的默认存储引擎是InnoDB,而不是MyISAM(有关这两种引擎的优劣,可参考51CTO之前的文章浅谈MySQL存储引擎选择 InnoDB还是MyISAM以及InnoDB还是MyISAM 再谈MySQL存储引擎的选择)

  ◆他所支持的数据类型比MySQL要少

  ◆它使用一套不同的客户机/服务器通信协议;

  ◆它提供了可扩展,插件化的架构,允许开发者只把需要的模块编译进去。(和Apache、PHP很像。有关Drizzle扩展性方面的优势,51CTO之前的文章从memcached看MySQL和关系数据库的未来中也有所提及)

  关于MySQL和Drizzle之间差异的更多信息可以参见 Michael "Monty" Widenius(MySQL创始人,在今年5月宣布要建立开源数据库联盟)博客上与此相关的文章 ,以及 Drizzle FAQ 。

  值得引起重视的一点是,Drizzle仍处在开发阶段,开发人员说他目前并不适于在生产环境使用。因此,如果要向你的老板或客户推荐数据库,目前还是应该用MySQL,PostgreSQL或SQLite。

  An Apple A Day

  Drizzle目前适用于Mac OS X,Linux和Solaris平台,需要GCC v4.1或以上版本支持;Windows平台暂时还没法使用Drizzle。首先,下载 Drizzle数据库服务器 (drizzle)和 Drizzle协议库 ( libdrizzle ) 这二者的源代码,解压缩,然后编译并安装到你的系统中,如下:

  shell> tar -xzvf libdrizzle-0.3.tar.gz shell> cd libdrizzle-0.3 shell> ./configure shell> make shell> make install shell> tar -xzvf drizzle-2009.06.1063.tar.gz shell> cd drizzle-2009.06.1063 shell> ./configure --with-libprotobuf-prefix=/usr/local shell> make shell> make install

  本文使用Drizzlev2009.06.1063和libdrizzle v0.3 。

  注意,Drizzle要用到 Google Protocol Buffers协议 ,因此,如果你还没有安装Google的这个协议,那就还得下载并把它编译到系统里。在Protocol Buffers的网站上有它的源文件和详细的安装指南。本文使用v2.0.3版本的Protocol Buffers库,而不是更新一些的v2.1.0 ,以避免与pthreads有关的一个bug 。

  默认情况下,Drizzle服务器将被安装在/ usr / local / sbin /drizzled目录,Drizzle客户端则是在/ usr / local / bin /drizzle。

  安装完成后,就要为数据库服务器创建一个非特权组和用户,如下:

  shell> groupadd drizzle shell> useradd -g drizzle drizzle

  另外还要创建一个目录以存放数据库文件,并给予适当的权限,如下:

  shell> mkdir /usr/local/drizzle shell> mkdir /usr/local/drizzle/data shell> cd /usr/local/drizzle shell> chown -R drizzle . shell> chgrp -R drizzle .

  然后,用以下命令启动Drizzle服务器:

  shell> /usr/local/sbin/drizzled --user=drizzle --basedir=/usr/local/drizzle/ --datadir=/usr/local/drizzle/data/ & InnoDB: The InnoDB memory heap is disabled InnoDB: Mutexes and rw_locks use GCC atomic builtins. InnoDB: The first specified data file ./ibdata1 did not exist: InnoDB: a new database to be created! 090630 10:29:42 InnoDB: Setting file ./ibdata1 size to 10 MB InnoDB: Database physically writes the file full: wait... 090630 10:29:42 InnoDB: Log file ./ib_logfile0 did not exist: new to be created InnoDB: Setting log file ./ib_logfile0 size to 5 MB InnoDB: Database physically writes the file full: wait... 090630 10:29:42 InnoDB: Log file ./ib_logfile1 did not exist: new to be created InnoDB: Setting log file ./ib_logfile1 size to 5 MB InnoDB: Database physically writes the file full: wait... InnoDB: Doublewrite buffer not found: creating new InnoDB: Doublewrite buffer created InnoDB: Creating foreign key constraint system tables InnoDB: Foreign key constraint system tables created 090630 10:29:43 InnoDB Plugin 1.0.3 started; log sequence number 0 /usr/local/sbin/drizzled: ready for connections. Version: '2009.06.1063' socket: '' port: 4427 Source distribution

  编译包的过程中也会生成一个和MySQL客户端非常类似的Drizzle客户端。按如下步骤启动它并进入Drizzle服务器:

  shell> /usr/local/bin/drizzle Welcome to the Drizzle client.. Commands end with ; or \g. Your Drizzle connection id is 24 Server version: 2009.06.1063 Source distribution Type 'help;' or '\h' for help. Type '\c' to clear the buffer. drizzle>

  现在,你就可以向服务器发出SQL命令了,就像用MySQL客户端那样。

  drizzle> SELECT VERSION(); +--------------+ | VERSION() | +--------------+ | 2009.06.1063 | +--------------+ 1 row in set (0 sec)

  我们先创建一个数据库并添加一张表:

  drizzle> CREATE DATABASE test; Query OK, 1 row affected (0 sec) drizzle> USE test; Database changed drizzle> CREATE TABLE items ( -> ItemID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -> ItemDesc VARCHAR(255) NOT NULL, -> ItemQty INT NOT NULL -> ); Query OK, 0 rows affected (0.01 sec)

  据Drizzle FAQ所述,Drizzle支持TEXT, BLOB, VARCHAR, VARBINARY, TIMESTAMP, DATETIME, DATE, TIME, ENUM, INT, DOUBLE以及DECIMAL 这些字段类型。通过MySQL,你可能已经对这其中的许多了如指掌了

  下面通过向表中填充一些记录来继续我们的示例演示:

  drizzle> INSERT INTO items (ItemDesc, ItemQty) VALUES ('Bacon', 4); Query OK, 1 row affected (0 sec) drizzle> INSERT INTO items (ItemDesc, ItemQty) VALUES ('Eggs', 3); Query OK, 1 row affected (0 sec) drizzle> INSERT INTO items (ItemDesc, ItemQty) VALUES ('Milk', 1); Query OK, 1 row affected (0 sec) drizzle> INSERT INTO items (ItemDesc, ItemQty) VALUES ('Apples', 6); Query OK, 1 row affected (0.01 sec)

  简单运行一个SELECT语句看看是否一切正常:

  drizzle> SELECT * FROM items; +--------+----------+---------+ | ItemID | ItemDesc | ItemQty | +--------+----------+---------+ | 1 | Bacon | 4 | | 2 | Eggs | 3 | | 3 | Milk | 1 | | 4 | Apples | 6 | +--------+----------+---------+ 4 rows in set (0 sec)

  下一步,我们就要使用PHP来做同样的事了!

  Drizzle PHP入门

  通过Drizzle PHP扩展,可以在PHP里获得全面的API来操纵Drizzle数据库。这一扩展目前由Eric Day, James Luedke以及其它人员维护,可以遵照PHP许可证从PECL里免费获得。虽然这个扩展目前还处于Beta阶段,但它已经涵盖了PHP应用程序中可能涉及到的各种常见任务。

  要开始使用了Drizzle PHP扩展(v0.4.0 ),用PECL自动安装程序就可以了,如下:

  shell> pecl install drizzle-beta

  或者,你也可以下载它的源代码,并将其编译成一个可加载的PHP模块,如下:

  shell> tar -xzvf drizzle-0.4.0.tar.gz shell> cd drizzle-0.4.0 shell> phpize shell> ./configure shell> make shell> make install

  至此,在你的PHP模块目录下应该就有了名为drizzle.so的一个可加载模块。在php.ini配置文件里启用此扩展,重新启动Web服务器,并用phpinfo()函数检查这一扩展是否已经启用:

  小提示

  下面的例子演示了用Drizzle PHP扩展执行SELECT语句查询数据库服务器,并将查询结果以HTML表格的格式输出。

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = drizzle_create(); // connect to database server $conn = drizzle_con_add_tcp($drizzle, $host, $port, $user, $pass, $db, 0) or die('ERROR: ' . drizzle_error($drizzle)); // execute query $sql = 'SELECT ItemDesc, ItemQty FROM items'; $result = @drizzle_query($conn, $sql) or die ('ERROR: ' . drizzle_con_error($conn)); // buffer result set drizzle_result_buffer($result) or die('ERROR: ' . drizzle_con_error($conn)); // check number of rows in result set and print if (drizzle_result_row_count($result)) { echo '< table>'; while (($row = drizzle_row_next($result))) { echo '< tr>'; echo '< td>' . $row[0] . '< /td>'; echo '< td>' . $row[1] . '< /td>'; echo '< /tr>'; } echo '< /table>'; } else { echo 'No records found'; } // free result set drizzle_result_free($result); // close connection drizzle_con_close($conn); ?> < /body> < /html>

  该脚本一开始就通过指定必要的信息来建立与数据库服务器的一个连接。这些信息包括服务器名称,服务器端口,用户名和密码,以及要查询的数据库名称。这些值都是用普通的PHP变量保存的。drizzle_create()函数会初始化一个Drizzle对象,这些连接时需要的参数则是通过 drizzle_con_add_tcp()函数添加进去的。这个函数返回一个连接标识符,用于接下来与数据库服务器间的通信。

  下一步是创建查询语句并执行。这是通过drizzle_query()函数实现的,它需要两个参数,一个是查询语句,另一个是连接标识符。 drizzle_query()函数的返回值是一个结果对象,代表着这次查询的结果。如果你愿意的话,可以使用 drizzle_result_buffer()函数缓存这个结果集;不过要注意,如果查询返回的结果集很大的话,这对内存的占用也是非常明显的。

  drizzle_result_row_count()函数返回缓存的结果集中记录的条数。这些记录可以用drizzle_row_next()函数检索,它能在结果集中迭代,并且以数组的形式获取每条结果。然后就可以通过数组符号访问各个字段了。

  当你处理完每个结果集之后,最好用drizzle_result_free()函数释放它所用的内存。若要彻底清理干净,则可使用drizzle_con_close()函数断开与Drizzle服务器的连接。

  使用面向对象

  你也可以用面向对象方式使用Drizzle API,之前所用的每个函数都对应于对象的一种方法。请看下面这段代码,它与之前那段是等价的:

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = new drizzle(); // connect to database server $conn = $drizzle->addTcp($host, $port, $user, $pass, $db, 0) or die('ERROR: ' . $drizzle->error()); // execute query $sql = 'SELECT ItemDesc, ItemQty FROM items'; $result = @$conn->query($sql) or die('ERROR: ' . $conn->error()); // buffer result set $result->buffer() or die('ERROR: ' . $conn->error()); // check number of rows in result set and print if ($result->rowCount()) { echo '< table>'; while (($row = $result->rowNext())) { echo '< tr>'; echo '< td>' . $row[0] . '< /td>'; echo '< td>' . $row[1] . '< /td>'; echo '< /tr>'; } echo '< /table>'; } else { echo 'No records found'; } // close connection $conn->close(); // deinitialize object unset($drizzle); ?> < /body> < /html>

  在这里,new关键字实例化了一个Drizzle对象,并且向这个对象的addTcp()方法传递了相关的连接信息。由此产生的 DrizzleCon对象提供了 query () 方法,可以用来在数据库服务器上执行查询。此外还有DrizzleResult对象也提供了一些方法来执行对结果集的获取、缓存、处理等操作。

  如果你仔细研究以上这两个脚本,就会发现它们在函数和方法命名以及代码结构上的许多相似之处。

  如提高运行效率,减小资源占用?

  如果你的SQL查询可能会返回大量的记录,那么就用无缓冲查询代替缓冲查询能提高效率。无缓冲查询消耗较少的内存,它还可以让你在查询完成执行前开始处理结果集。不过这也有缺点,无缓冲查询无法使用drizzle_result_row_count()这样的函数,因为PHP的缓存里没有一个完整的结果集,自然也就无法计算它有多少条记录了。

  下面的示例使用的是Drizzle 扩展的无缓冲查询:

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = drizzle_create(); // connect to database server $conn = drizzle_con_add_tcp($drizzle, $host, $port, $user, $pass, $db, 0) or die('ERROR: ' . drizzle_error($drizzle)); // execute query $sql = 'SELECT ItemDesc, ItemQty FROM items'; $result = @drizzle_query($conn, $sql) or die('ERROR: ' . drizzle_con_error($conn)); // skip field names drizzle_column_skip($result); // iterate over records and fields echo '< table>'; while (($row = drizzle_row_read($result))) { echo '< tr>'; while ($fields = drizzle_field_read($result)) { // if this is the end of the record // go to next record if (drizzle_result_return_code($result) == DRIZZLE_RETURN_ROW_END) { break; } echo '< td>' . $fields[0] . '< /td>'; } echo '< /tr>'; } echo '< /table>'; // free result set drizzle_result_free($result); // close connection drizzle_con_close($conn); ?> < /body> < /html>

  前半部分的代码与之前你所看到的是相同的。但是,查询执行完后,drizzle_result_buffer()并没有被调用,而是直接使用了 drizzle_row_read()和drizzle_field_read()方法来遍历无缓冲结果集并输出各个字段的值。另外还注意 drizzle_column_skip()这个函数,它用来在返回的数据包里跳过列的名字。

  下面是用面向对象接口实现了相同功能的脚本:

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = new drizzle(); // connect to database server $conn = $drizzle->addTcp($host, $port, $user, $pass, $db, 0) or die('ERROR: ' . $drizzle->error()); // execute query $sql = 'SELECT ItemDesc, ItemQty FROM items'; $result = @$conn->query($sql) or die('ERROR: ' . $conn->error()); // skip field names $result->columnSkip(); // iterate over records and fields echo '< table>'; while (($row = $result->rowRead())) { echo '< tr>'; while ($fields = $result->fieldRead()) { // if this is the end of the record // go to next record if ($result->returnCode() == DRIZZLE_RETURN_ROW_END) { break; } echo '< td>' . $fields[0] . '< /td>'; } echo '< /tr>'; } echo '< /table>'; // close connection $conn->close(); // deinitialize object unset($drizzle); ?> < /body> < /html>

  添加和删除

  你也可以使用drizzle_query()函数,或者是query()方法来执行INSERT, UPDATE 和 DELETE查询。下面这个例子演示了执行一个INSERT查询并通过insertId()方法获取新插入的这条记录的ID号。

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = new drizzle(); // connect to database server $conn = $drizzle->addTcp($host, $port, $user, $pass, $db, 0) or die('ERROR: ' . $drizzle->error()); // execute query $sql = "INSERT INTO items (ItemDesc, ItemQty) VALUES ('Jam', '2')"; $result = @$conn->query($sql) or die('ERROR: ' . $conn->error()); // get record ID echo 'Record inserted with ID: ' . $result->insertId(); // close connection $conn->close(); // deinitialize object unset($drizzle); ?> < /body> < /html>

  下面是另外一个例子,它执行一个DELETE语句,并用affectedRows()方法函数返回受影响的行数。

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = new drizzle(); // connect to database server $conn = $drizzle->addTcp($host, $port, $user, $pass, $db, 0) or die('ERROR: ' . $drizzle->error()); // execute query $sql = "DELETE FROM items WHERE ItemID > 4"; $result = @$conn->query($sql) or die('ERROR: ' . $conn->error()); // get number of records affected echo $result->affectedRows() . ' record(s) deleted'; // close connection $conn->close(); // deinitialize object unset($drizzle); ?> < /body> < /html>

  Drizzle PHP扩展还提供了drizzle_escape_string()函数和excape()方法,它可以在把用户的输入插入到查询语句前先对其进行转义。处理用户提交的数据是非常重要的安全措施,这样才能减小受到SQL注入攻击的危险。在下面这一个例子里,我们提供了一个不安全的Web表单,用户可以通过这个表单直接向数据库里添加新的条目,从而示范了excape()函数的使用。

  < html> < head> < style type="text/css"> table,tr,td { border: solid 1px black; border-collapse: collapse; padding: 5px; } < /style> < /head> < body> < h2>List Items< /h2> < ?php // set connection parameters $host = 'localhost'; $port = 4427; $user = 'root'; $pass = 'guessme'; $db = 'test'; // create drizzle object $drizzle = new drizzle(); // connect to database server $conn = $drizzle->addTcp($host, $port, $user, $pass, $db, 0) or die('ERROR: ' . $drizzle->error()); // check if form submitted // sanitize input and add record if ($_POST['submit']) { // escape input strings $desc = $drizzle->escape($_POST['desc']); $qty = $drizzle->escape($_POST['qty']); // execute query $sql = "INSERT INTO items (ItemDesc, ItemQty) VALUES ('$desc', '$qty')"; $result = @$conn->query($sql) or die('ERROR: ' . $conn->error()); // get record ID echo 'Record inserted with ID: ' . $result->insertId(); } // execute query $sql = 'SELECT ItemID, ItemDesc, ItemQty FROM items'; $result = @$conn->query($sql) or die('ERROR: ' . $conn->error()); // buffer result set $result->buffer() or die('ERROR: ' . $conn->error()); // check number of rows in result set and print if ($result->rowCount()) { echo '< table>'; echo '< tr>'; echo '< td>ID< /td>'; echo '< td>Name< /td>'; echo '< td>Quantity< /td>'; echo '< /tr>'; while (($row = $result->rowNext())) { echo '< tr>'; echo '< td>' . $row[0] . '< /td>'; echo '< td>' . $row[1] . '< /td>'; echo '< td>' . $row[2] . '< /td>'; echo '< /tr>'; } echo '< /table>'; } else { echo 'No records found'; } // close connection $conn->close(); // deinitialize object unset($drizzle); ?> < h2>Add Item< /h2> < form method="post" action="< ?php echo htmlentities($_SERVER['PHP_SELF']); ?>"> Item name: < br /> < input type="text" name="desc"> < br /> Item quantity: < br /> < input type="text" name="qty"> < br /> < input type="submit" name="submit" value="Save"> < /form> < /body> < /html>

  注意这段代码在将用户输入值插入到SQL查询语句中之前都先调用了escape()方法;它会对用户输入数据中的特殊字符进行处理。

  版本控制

  Drizzle扩展还带有许多能提供与当前Drizzle客户端、服务器以及协议的版本有关的信息的函数。把它与Drizzle的 information_schema数据库里的信息结合起来可以让我们更清楚地看到Drizzle服务器内部到底是如何运作的。

  这段脚本通过查询information_schema这个特殊的数据库来获取这台服务器上的数据库和表的信息,此外还可以获取到全局状态变量的值,比如服务器的运行时间、连接的线程数量、已开打的表格数等。它还示范了version(),serverVersion(),以及 protocolVersion()方法,它们分别返回Drizzle客户端、服务器和协议的版本号。

  Drizzle 扩展还提供了许多能帮你处理连接错误、查询错误的函数。drizzle_error()和drizzle_error_code()函数返回上一次数据库连接所产生的错误信息和错误代码,而drizzle_con_error()和drizzle_con_error_code()函数返回上一次查询所产生的的错误信息和错误代码。当然,这些函数也有相应的面向对象接口,你可以看看之前的例子看看它们是如何使用的。

  我要介绍的内容就是这些了。在前面几页里,我介绍了Drizzle这个新兴的、轻量的、为云应用特别设计的MySQL分支,并演示了在PHP应用程序里使用它是多么简单的事情。虽然Drizzle PHP扩展(更不用说Drizzle本身)还在开发阶段,但是它仍然已经提供了非常全面的API来执行查询语句、检查结果集、处理错误。有空的时候试试它吧,再与我分享一下你的使用感受!

论坛徽章:
0
2 [报告]
发表于 2010-08-11 12:17 |只看该作者
谢谢LZ分享资料,如果排一下版效果会更好。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP