缘起: 在数据驱动的web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载。缓存是解决这个问题的好办法。但是ASP.NET中的虽然已经可以实现对页面局部进行缓存,但还是不够灵活。此时Memcached或许是你想要的。


Memcached是什么?

Memcached是由Danga Interactive开发的,高性能的,分布式的内存对象缓存系统,用于在动态应用中减少数据库负载,提升访问速度。


Memcached能缓存什么?

通过在内存里维护一个统一的巨大的hash表,Memcached能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。


Memcached快么?

非常快。Memcached使用了libevent(如果可以的话,在linux下使用epoll)来均衡任何数量的打开链接,使用非阻塞的网络I/O, 对内部对象实现引用计数(因此,针对多样的客户端,对象可以处在多样的状态), 使用自己的页块分配器和哈希表, 因此虚拟内存不会产生碎片并且虚拟内存分配的时间复杂度可以保证为O(1).。


Danga Interactive为提升Danga Interactive的速度研发了Memcached。目前,LiveJournal.com每天已经在向一百万用户提供多达两千万次的页面访问。而这 些,是由一个由web服务器和数据库服务器组成的集群完成的。Memcached几乎完全放弃了任何数据都从数据库读取的方式,同时,它还缩短了用户查看 页面的速度、更好的资源分配方式,以及Memcache失效时对数据库的访问速度。


Memcached的特点Memcached的缓存是一种分布式的,可以让不同主机上的多个用户同时访问, 因此解决了共享内存只能单机应用的局限,更不会出现使用数据库做类似事情的时候,磁盘开销和阻塞的发生。



一、win32的安装方法


                1. 下载memcache的windows稳定版,解压放某个盘下面,比如在c:\memcached

                2. 在终端(也即cmd命令界面)下输入 'c:\memcached\memcached.exe -d install' 安装

                3. 再输入: 'c:\memcached\memcached.exe -d start' 启动

          NOTE: 以后memcached将作为windows的一个服务每次开机时自动启动。

                4. 在C:\winnt\php.ini 加入一行 'extension=php_memcache.dll'

                5. 下载pecl的PECL 5.2.4 Win32 binaries模块包,解压缩后将其中的memcache.dll考到c:\php\ext 中,(也不一定是c盘的PHP文件夹下,主要是看你当初把PHP安装到哪个盘符下面了)

                        NOTE: php和pecl的版本要一致。

                6.重新启动Apache,然后查看一下phpinfo,如果有memcache,那么就说明安装成功!


二、使用方法(可以查看手册):



CODE:


​[Copy to clipboard]​


<?php


$memcache = new Memcache;

$memcache->connect('localhost', 11211) or die ("Could not connect");


$version = $memcache->getVersion();

echo "Server's version: ".$version."<br/>n";


$tmp_object = new stdClass;

$tmp_object->str_attr = 'test';

$tmp_object->int_attr = 123;


$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");

echo "Store data in the cache (data will expire in 10 seconds)<br/>n";


$get_result = $memcache->get('key');

echo "Data from the cache:<br/>n";


var_dump($get_result);


?>

MemCache的目录如下,其实代码调用非常简单,主要会用到的方法有 add()、get()、replace() 和 delete(),方法说明如下:



CODE:


​[Copy to clipboard]​


Memcache::add -- Add an item to the server 

add ($key, $val, $exp = 0)

往 memcached 中写入对象,$key 是对象的唯一标识符,$val 是写入的对象数据,$exp 为过期时间,单位为秒,默认为不限时间;

Memcache::delete -- Delete item from the server 

delete ($key, $time = 0)

删除 memcached 中标识符为 $key 的对象,$time 为可选参数,表示删除之前需要等待多长时间。


Memcache::get -- Retrieve item from the server 

get ($key)

从 memcached 中获取对象数据,通过对象的唯一标识符 $key 获取;


Memcache::replace -- Replace value of the existing item 

replace ($key, $value, $exp=0)

使用 $value 替换 memcached 中标识符为 $key 的对象内容,参数与 add() 方法一样,只有 $key 对象存在的情况下才会起作用;


主要的来说一说:bool Memcache::set ( string key, mixed var [, int flag [, int expire]] ) -- 保存数据到Memcache服务器上

string key:惟一关键字

             关键字用于从缓存中检索相关数据。如果每条记录都有一个惟一 ID,则可能足以作为缓存关键字,但是您可以策划其他模式来满足需求。 


mixed var :要缓存的变量 

变量可以是任意类型,只要它可以被序列化为持久的变量并且可以取消序列化为检索的变量。 

int flag :用于启用通过 zlib 进行动态压缩的布尔值 

使用 MEMCACHE_COMPRESSED 来压缩信息到内存中 —— 虽然处理数据时都要以保存和恢复为代价。 

int expire:以秒为单位指定的过期时间 

当缓存的数据过期时,它将被自动删除。如果将此值设为 0,则该条目永远不会在缓存中过期。使用 Memcache API delete() 函数删除这样一个永久对象。 

例如:

<?php

$memcache_obj = new Memcache;

$memcache_obj->connect('localhost', 11211);

$memcache_obj->set('var_key', 'some really big variable', MEMCACHE_COMPRESSED, 50);

echo $memcache_obj->get('var_key');

?>

////////////////////////////////////////////////////////////////////////////////////////////


Memcache::connect -- 打开一个到Memcache的连接

Memcache::pconnect -- 打开一个到Memcache的长连接

Memcache::close -- 关闭一个Memcache的连接

Memcache::flush -- 刷新所有Memcache服务器上保存的项目(类似于删除所有的保存的项目)

Memcache::getStats -- 获取当前Memcache服务器运行的状态


          另外为了看到所有slabs组的统计数据以及统计情况: 通过telnet 127.0.0.1 11211 可以连上memcached, 键入命令 stats slabs 可以看到所有slabs组的统计数据以及统计情况了.




[/color]

<?php

///////myCache CLASS    BEGIN////////////////////////

class myCache extends Memcache  {   

    function getInstance() {

        static $Object;     

        if ( ! isset( $Object )) {

        $Object = new Memcache;

        $Object->connect('localhost',11211);

        }       

        return $Object;      

    }      

    function close() {

        if ( isset($Object) ) {

            $Object->close();

            $Object = null; 

        }

    }

}

///////myCache CLASS    END////////////////////////


///////MYDATUM CLASS    BEGIN////////////////////////

class myDatum {//为了数组的可扩展性,凡是被注释掉的部分都是为了减少对数组的关键字限定的问题

    /*

    var $values = array(

        'description' => null,

        'price'       => null,

        'weight'      => null

        );

    */

    var $values        = array();

    var $settings    =     array();    

    function myDatum($settings) {

        foreach ($settings as $key => $value) {

            /*

            if ( !array_key_exists( $key, $this->values ) ) {

                die( "未知的属性: $key" );

            }

            */

            

            $this->values{ $key } = $value;

        }

    }

    

    function set( $key=null, $value=null ) {

        if ( is_null( $key ) ) {

            die( "关键字不能为空" );

        }

        /*

        if ( ! array_key_exists( $key, $this->values ) ) {

            die( "未知的属性: $key" );

        }

        */

        

        if ( ! is_null( $value ) ) {

            $this->values{ $key } = $value;

        }

        

        return( $this->values{ $key } );

    }

    

    function get( $key=null ) {

        return( $this->set( $key, null ) );

    }

}

///////MYDATUM CLASS    END////////////////////////


//////////////一般意义上的使用    ///////////////////

$datum = new myDatum(

    array(

        'description' => 'ball',

        'price'       => 1.50,

        'weight'      => 1021212121

    )

);

echo $datum->get( 'price' ) . "<BR />";


//////////////将对象放入缓存中    ///////////////////////////

$cache = myCache::getInstance();

if ( $cache->set('info', $datum,false,40)) {

    echo('对象已经被缓存' . "<BR />"); 

}

$cache->close();


//////////////从缓存中调用一个对象    ///////////////////////////

$new_cache = myCache::getInstance();

$new_datum = $new_cache->get('info');

    echo $new_datum->get('weight') . "<BR />";


ECHO "<PRE>";

PRINT_R($new_datum);

ECHO "</PRE>";

EXIT;

if ($new_datum !== false) {

    echo ( '从缓存中调用一个对象:' . "<BR />");

    echo $new_datum->get('weight') . "<BR />";

}

ECHO "<PRE>";

print_r($new_cache->getExtendedStats());

ECHO "</PRE>";

$new_cache->close();

?>

     myCache 类是单件并提供指向缓存的单独的开放连接。myDatum 类代表了所有对象:它有一系列属性(实现为散列),以及一个 getter 和一个 setter 方法。要创建 myDatum 对象,请把一个值散列传递给其构造函数。要设定属性,请调用带有属性名的 set() 作为字符串和值。要获得属性,请调用带有属性名的 get()。