如果要用 PHP 透過 HandlerSocket 存取 MySQL ,必須先安裝好 php-handlersocket 這個 PHP Extension ,在 Debian Squeeze 安裝 MySQL HandlerSocket Plugin 有提到安裝方法,安裝完之後有以下 function 可以用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
HandlerSocket { /* Constants */ const HandlerSocket::PRIMARY; /* Methods */ __construct ( string $host, int $port, [ array $options ]) public bool openIndex ( int $id, string $db, string $table, string $index, string $fields ) public mixed executeSingle ( int $id, string $op, array $fields [, int $limit, int $skip, strint $modop, array $values ] ) public mixed executeMulti ( array $requests ) public int executeUpdate ( int $id, string $op, array $fields, array $values [, int $limit, int $skip ] ) public int executeDelete ( int $id, string $op, array $fields [, int $limit, int $skip ] ) public bool executeInsert ( int $id, array $values ) public string getError ( void ) } |
有鑑於 php-handlersocket 提供的 function 使用起來不是很直覺,所以我寫了一個 wrapper 方便使用,以下是範例,首先必須先建立一個資料表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
-- -- DB SCHEME -- CREATE TABLE IF NOT EXISTS `user` ( `user_id` int(10) unsigned NOT NULL, `user_name` varchar(50) DEFAULT NULL, `user_email` varchar(255) DEFAULT NULL, `created` datetime DEFAULT NULL, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Insert DATA -- INSERT INTO `user` (`user_id`, `user_name`, `user_email`, `created`) VALUES (101, 'foo', 'foo@example.com', '2011-03-13 17:50:40'), (102, 'cat', 'cat@example.com', '2011-03-30 18:13:11'), (111, 'dog', 'dog@example.com', '0000-00-00 00:00:00'), (112, 'bar', 'bar@example.com', NULL); |
接下來就可以開使用程式把上面的 MySQL Storage Engine (InnoDB) 當成 NoSQL DB 使用了。你可以直接用 php-handlersocket 這個 extension 本身提供的 PHP function 來寫,或是用我寫的 php-handlersocket-wrapper,來簡化操作。
以下程式,是 php-handlersocket-wrapper 的範例,可以從這邊下載。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?php require('handlersocket_wrapper.php'); $db_host = '127.0.0.1'; $port_read = 9998; $port_write = 9999; $dbname = 'test'; $table = 'user'; $indexid = 1; /* 初始化連線設定 */ $hsr = new HandlerScoketWrapper($db_host, $port_read, $dbname, $table); /* 只拿 user_id, user_email 兩個欄位的資料 */ $hsr->init(array('user_id', 'user_email'), $indexid); $result = $hsr->get('101'); /* 只要 DB 中有資料,就可以用 primary key 拿出來 */ var_dump($result); /* 當然也可以一次拿多筆資料 */ $result = $hsr->get(array('101', '102', '111')); var_dump($result); /* 如果要寫入資料,要用 $port_write 連接*/ $hsw = new HandlerScoketWrapper($db_host, $port_write, $dbname, $table); /* 如果想要拿的欄位和上次建立連線不相同, index id 的值要不同,這次是拿 user_id, user_name, user_email 三個欄位的資料 */ $hsw->init(array('user_id', 'user_name', 'user_email'), $indexid + 1); /* 新增一筆資料,第一個參數是 pkey, 後面是值,幾個欄位就幾個陣列元素 */ $result = $hsw->add(array('104', 'cool', 'cool@example.com')); var_dump($result); /* $port_write 一樣可以哪資料 */ $result = $hsw->get('104'); var_dump($result); /* update 資料,第一個參數是 pkey, 後面是要 update 的資料 */ $data = array('hot', 'hot@example.com'); $result = $hsw->update('104', $data); /* first param is primary key, second param is data (as an array) */ var_dump($result); /* 用 pkey 刪掉資料 */ $status = $hsw->del('104'); var_dump($status); |
非常簡單好用,不過也看到了缺點…目前看來沒有認證機制。
Hi, Mic
index id 的作用,並不是 AUTO INCREMENT 的 id ,這個問題一開始我也覺得很疑惑,後來在寫 wrapper 的時候,查文件才知道 HandlerSocket plugin 在開啟連線的時候,會根據這組 index id 來決定要開啟的欄位,假設 index id 是 1 的時候,
[sourcecode lang=”php”]
$indexid = 1;
$hsw->init(array(‘user_id’, ‘user_name’, ‘user_email’), $indexid);
[/sourcecode]
這樣代表 index id = 1 的這個連線,會存取(有沒有寫入取決於是不是用 write port ) user_id, user_name, user_email 這三個欄位 ,
[sourcecode lang=”php”]
$hsw->init(array(‘user_name’, ‘user_email’), $indexid + 1);
[/sourcecode]
則是代表 index id = 2 的這個連線,會存取 user_name, user_email 這兩個欄位 ,所以和上一個 index id = 1 的連線相比,在拿或是寫的時候,這個連線不會碰到 user_id 的欄位。
可以用下面這個方法:
[sourcecode lang=”php”]
$hs1 = new HandlerScoketWrapper($db_host, $port, $dbname, $table);
$hs1->init(array(‘user_id’, ‘user_email’), $indexid);
$hs2 = new HandlerScoketWrapper($db_host, $port, $dbname, $table);
$hs2->init(array(‘user_name’, ‘user_email’), $indexid);
[/sourcecode]
建立不同的連線,以進行最佳化。
/**
* https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/blob/master/docs-en/protocol.en.txt
* …
* Once an ‘open_index’ request is issued, the HandlerSocket plugin opens the
* specified index and keep it open until the client connection is closed. Each
* open index is identified by “indexid”. If “indexid” is already open, the old
* open index is closed. You can open the same combination of “dbname”
* “tablename” “indexname” multple times, possibly with different “columns”.
* For efficiency, keep “indexid” small as far as possible.
* …
*
*/
可以問一下為什麼要有 $indexid 嗎?這是auto increase id?