用户名:
密 码: 记住
您当前的位置:首页 > 网络编程 > php教程

PHP中常用的缓存技术介绍

时间:2015-01-23  来源:西部数据  作者:西部数据

数据缓存:这里所说的数据缓存是指数据库查询缓存,每次访问页面的时候,都会先检测相应的缓存数据是否存在,如果不存在,就连接数据库,得到数据,并把查询结果序列化后保存到文件中,以后同样的查询结果就直接从缓存文件中获得,代码如下:

  1. <?php 
  2. $sql = 'SELECT * FROM users'
  3. $key = md5($sql);   //memcached 对象标识符 
  4. if ( !($datas = $mc->get($key)) ) { 
  5.     //    在 memcached 中未获取到缓存数据,则使用数据库查询获取记录集。 
  6.     echo "n".str_pad('Read datas from MySQL.', 60, '_')."n"
  7.     $conn = mysql_connect('localhost''test''test'); 
  8.     mysql_select_db('test'); 
  9.     $result = mysql_query($sql); 
  10.       while ($row = mysql_fetch_object($result)) 
  11.         $datas[] = $row
  12.     //    将数据库中获取到的结果集数据保存到 memcached 中,以供下次访问时使用。 
  13.     $mc->add($key$datas); 
  14. else { 
  15.       echo "n".str_pad('Read datas from memcached.', 60, '_')."n"
  16. var_dump($datas); 
  17. ?> 

页面缓存:每次访问页面的时候,都会先检测相应的缓存页面文件是否存在,如果不存在,就连接数据库,得到数据,显示页面并同时生成缓存页面文件,这样下次访问的时候页面文件就发挥作用了,模板引擎和网上常见的一些缓存类通常有此功能,代码如下:

  1. <?php 
  2. define('DIRECTORY_SEPARATOR','/'); 
  3. define('FOPEN_WRITE_CREATE_DESTRUCTIVE','wb'); 
  4. define('FOPEN_WRITE_CREATE','ab'); 
  5. define('DIR_WRITE_MODE', 0777); 
  6. class FileCache { 
  7.  
  8.  /** 
  9.      * 缓存路径 
  10.      * 
  11.      * @access private 
  12.      * @var string 
  13.      */ 
  14.  private $_cache_path
  15.  
  16.  /** 
  17.      * 缓存过期时间,单位是秒second 
  18.      * 
  19.      * @access private 
  20.      * @var int 
  21.      */ 
  22.  private $_cache_expire
  23.  
  24.  /** 
  25.      * 解析函数,设置缓存过期实践和存储路径 
  26.      *  
  27.      * @access public 
  28.      * @return void 
  29.      */ 
  30.  public function __construct($expire$cache_path
  31.  { 
  32.   $this->_cache_expire = $expire
  33.   $this->_cache_path = $cache_path
  34.  } 
  35.  
  36.  /** 
  37.      * 缓存文件名 
  38.      *  
  39.      * @access public 
  40.      * @param  string $key 
  41.      * @return void 
  42.      */ 
  43.  private function _file($key
  44.  { 
  45.   return $this->_cache_path . md5($key); 
  46.  } 
  47.  
  48.  /** 
  49.      * 设置缓存 
  50.      *  
  51.      * @access public 
  52.      * @param  string $key 缓存的唯一键 
  53.      * @param  string $data 缓存的内容 
  54.      * @return bool 
  55.      */ 
  56.  public function set($key$data
  57.  { 
  58.   $value = serialize($data); 
  59.    
  60.   $file = $this->_file($key); 
  61.    
  62.      return $this->write_file($file$value); 
  63.  } 
  64.  
  65.  /** 
  66.      * 获取缓存 
  67.      *  
  68.      * @access public 
  69.      * @param  string $key 缓存的唯一键 
  70.      * @return mixed 
  71.      */ 
  72.  public function get($key
  73.  { 
  74.   $file = $this->_file($key); 
  75.    
  76.   /** 文件不存在或目录不可写 */ 
  77.   if (!file_exists($file) || !$this->is_really_writable($file)) 
  78.   { 
  79.    return false; 
  80.   } 
  81.    
  82.   /** 缓存没有过期,仍然可用 */ 
  83.   if ( time() < (filemtime($file) + $this->_cache_expire) )  
  84.   { 
  85.     
  86.    $data = $this->read_file($file); 
  87.     
  88.    if(FALSE !== $data
  89.    { 
  90.     return unserialize($data); 
  91.    } 
  92.     
  93.    return FALSE; 
  94.   } 
  95.    
  96.   /** 缓存过期,删除之 */ 
  97.   @unlink($file); 
  98.   return FALSE; 
  99.   } 
  100.    
  101.   function read_file($file
  102.  { 
  103.   if ( ! file_exists($file)) 
  104.   { 
  105.    return FALSE; 
  106.   } 
  107.  
  108.   if (function_exists('file_get_contents')) 
  109.   { 
  110.    return file_get_contents($file);   
  111.   } 
  112.  
  113.   if ( ! $fp = @fopen($file, FOPEN_READ)) 
  114.   { 
  115.    return FALSE; 
  116.   } 
  117.    
  118.   flock($fp, LOCK_SH);//读取之前加上共享锁 
  119.  
  120.   $data = ''
  121.   if (filesize($file) > 0) 
  122.   { 
  123.    $data =& fread($fpfilesize($file)); 
  124.   } 
  125.  
  126.   flock($fp, LOCK_UN);//释放锁 
  127.   fclose($fp); 
  128.  
  129.   return $data
  130.  } 
  131.  
  132.   function write_file($path$data$mode = FOPEN_WRITE_CREATE_DESTRUCTIVE) 
  133.  { 
  134.   if ( ! $fp = @fopen($path$mode)) 
  135.   { 
  136.    return FALSE; 
  137.   } 
  138.    
  139.   flock($fp, LOCK_EX); 
  140.   fwrite($fp$data); 
  141.   flock($fp, LOCK_UN); 
  142.   fclose($fp);  
  143.  
  144.   return TRUE; 
  145.  } 
  146.  function is_really_writable($file)//兼容各平台判断文件是否有写入权限 
  147.  {  
  148.   // If we're on a Unix server with safe_mode off we call is_writable 
  149.   if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE) 
  150.   { 
  151.    return is_writable($file); 
  152.   } 
  153.  
  154.   // For windows servers and safe_mode "on" installations we'll actually 
  155.   // write a file then read it.  Bah... 
  156.   if (is_dir($file)) 
  157.   { 
  158.    $file = rtrim($file'/').'/'.md5(rand(1,100)); 
  159.  
  160.    if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) 
  161.    { 
  162.     return FALSE; 
  163.    } 
  164.  
  165.    fclose($fp); 
  166.    @chmod($file, DIR_WRITE_MODE); 
  167.    @unlink($file); 
  168.    return TRUE; 
  169.   } 
  170.   elseif (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE) 
  171.   { 
  172.    return FALSE; 
  173.   } 
  174.  
  175.   fclose($fp); 
  176.   return TRUE; 
  177.  } 
  178. $cache = new FileCache(30,'cache/'); 
  179. $cache->set('test','this is a test.'); 
  180. print $cache->get('test'); 
  181. /* End of file FlieCache.php */ 

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

dbcached 是一款基于 Memcached 和 NMDB 的分布式 key-value 数据库内存缓存系统.

以上的缓存技术虽然能很好的解决频繁查询数据库的问题,但其缺点在在于数据无时效性,下面我给出我在项目中常用的方法,代码如下:

  1. class MemcacheModel { 
  2. private $mc = null; 
  3. /** 
  4. * 构造方法,用于添加服务器并创建memcahced对象 
  5. */ 
  6. function __construct(){ 
  7. $params = func_get_args(); 
  8. $mc = new Memcache; 
  9. //如果有多个memcache服务器 
  10. ifcount($params) > 1){ 
  11. foreach ($params as $v){ 
  12. call_user_func_array(array($mc'addServer'), $v); 
  13. //如果只有一个memcache服务器 
  14. else { 
  15. call_user_func_array(array($mc'addServer'), $params[0]); 
  16. $this->mc=$mc
  17. /** 
  18. * 获取memcached对象 
  19. * @return object memcached对象 
  20. */ 
  21. function getMem(){ 
  22. return $this->mc; 
  23. /** 
  24. * 检查mem是否连接成功 
  25. * @return bool 连接成功返回true,否则返回false 
  26. */ 
  27. function mem_connect_error(){ 
  28. $stats=$this->mc->getStats(); 
  29. if(emptyempty($stats)){ 
  30. return false; 
  31. }else
  32. return true; 
  33. private function addKey($tabName$key){ 
  34. $keys=$this->mc->get($tabName); 
  35. if(emptyempty($keys)){ 
  36. $keys=array(); 
  37. //如果key不存在,就添加一个 
  38. if(!in_array($key$keys)) { 
  39. $keys[]=$key;  //将新的key添加到本表的keys中 
  40. $this->mc->set($tabName$keys, MEMCACHE_COMPRESSED, 0); 
  41. return true;   //不存在返回true 
  42. }else
  43. return false;  //存在返回false 
  44. /** 
  45. * 向memcache中添加数据 
  46. * @param string $tabName 需要缓存数据表的表名 
  47. * @param string $sql 使用sql作为memcache的key 
  48. * @param mixed $data 需要缓存的数据 
  49. */ 
  50. function addCache($tabName$sql$data){ 
  51. $key=md5($sql); 
  52. //如果不存在 
  53. if($this->addKey($tabName$key)){ 
  54. $this->mc->set($key$data, MEMCACHE_COMPRESSED, 0); 
  55. /** 
  56. * 获取memcahce中保存的数据 
  57. * @param string $sql 使用SQL的key 
  58. * @return mixed 返回缓存中的数据 
  59. */ 
  60. function getCache($sql){ 
  61. $key=md5($sql); 
  62. return $this->mc->get($key); 
  63.  
  64. /** 
  65. * 删除和同一个表相关的所有缓存 
  66. * @param string $tabName 数据表的表名 
  67. */  
  68. function delCache($tabName){ 
  69. $keys=$this->mc->get($tabName); 
  70. //删除同一个表的所有缓存 
  71. if(!emptyempty($keys)){ 
  72. foreach($keys as $key){ 
  73. $this->mc->delete($key, 0); //0 表示立刻删除 
  74. //删除表的所有sql的key 
  75. $this->mc->delete($tabName, 0);  
  76. /** 
  77. * 删除单独一个语句的缓存 
  78. * @param string $sql 执行的SQL语句 
  79. */ 
  80. function delone($sql){ 
  81. $key=md5($sql); 
  82. $this->mc->delete($key, 0); //0 表示立刻删除 

时间触发缓存:检查文件是否存在并且时间戳小于设置的过期时间,如果文件修改的时间戳比当前时间戳减去过期时间戳大,那么就用缓存,否则更新缓存.

设定时间内不去判断数据是否要更新,过了设定时间再更新缓存,以上只适合对时效性要求不高的情况下使用,否则请看下面.

内容触发缓存:当插入数据或更新数据时,强制更新缓存.

在这里我们可以看到,当有大量数据频繁需要更新时,最后都要涉及磁盘读写操作,怎么解决呢?我在日常项目中,通常并不缓存所有内容,而是缓存一部分不经常变的内容来解决,但在大负荷的情况下,最好要用共享内存做缓存系统.

到这里PHP缓存也许有点解决方案了,但其缺点是,因为每次请求仍然要经过PHP解析,在大负荷的情况下效率问题还是比效严重,在这种情况下,也许会用到静态缓存.

静态缓存:这里所说的静态缓存是指HTML缓存,HTML缓存一般是无需判断数据是否要更新的,因为通常在使用HTML的场合一般是不经常变动内容的页面,数据更新的时候把HTML也强制更新一下就可以了.

也有像thinkphp的静态缓存,ThinkPHP官方手册写道静态规则的定义有三种方式,代码如下:

  1. Return Array( 
  2.  
  3. ‘ActionName’=>array(‘静态规则’,’静态缓存有效期’,’附加规则’), //第一种 
  4.  
  5. ‘ModuleName:ActionName’=>array(‘静态规则’,’静态缓存有效期’,’附加规则’),//第二种 
  6.  
  7. ‘*’=>array(‘静态规则’,’静态缓存有效期’,’附加规则’),//第三种 
  8.  
  9. …更多操作的静态规则 
  10.  

第一种是定义全局的操作静态规则,例如定义所有的read操作的静态规则为:'read'=>array('{id}','60').

其中,{id} 表示取$_GET[‘id’] 为静态缓存文件名,第二个参数表示缓存60秒.

第二种是定义某个模块的操作的静态规则,例如,我们需要定义Blog模块的read操作进行静态缓存.

‘Blog:read’=>array(‘{id}’,-1).

第三种方式是定义全局的静态缓存规则,这个属于特殊情况下的使用,任何模块的操作都适用,例如:

‘*’=>array(‘{$_SERVER.REQUEST_URI|md5}’),根据当前的URL进行缓存。

我这里在静态缓存规则文件htmls.php中写,代码如下:

<?php return array(   'getHtml' => array('{:action}', -1),//-1表示永久缓存  );?>   

SMARTY缓存,代码如下:

  1. <?php 
  2. require('./smarty/Smarty.class.php'); 
  3. $smarty = new Smarty; 
  4.  
  5. $smarty->caching = true; 
  6.  
  7. if(!$smarty->is_cached('index.tpl')) { 
  8.     // No cache available, do variable assignments here. 
  9.     $contents = get_database_contents(); 
  10.     $smarty->assign($contents); 
  11. $smarty->display('index.tpl'); 
  12. ?> 
来顶一下
返回首页
返回首页
推荐资讯
WiFi太不安全:7岁女孩11分钟内入侵公共网络 WiFi太不安全:7岁女孩11分钟内入侵近期刚刚发布研究说WiFi网络能获得人们手机里多少私人信息,
不服跑个分?人工智能也出现“刷分”乱象 不服跑个分?人工智能也出现“刷分2014年,人工智能领域突然爆发,成为了科研和科技创业的热门
相关文章
栏目更新
栏目热门