數據緩存:這里所說的數據緩存是指數據庫查詢緩存,每次訪問頁面的時候,都會先檢測相應的緩存數據是否存在,如果不存在,就連接數據庫,得到數據,并把查詢結果序列化后保存到文件中,以后同樣的查詢結果就直接從緩存文件中獲得,代碼如下:
- <?php
- $sql = 'SELECT * FROM users';
- $key = md5($sql); //memcached 對象標識符
- if ( !($datas = $mc->get($key)) ) {
- // 在 memcached 中未獲取到緩存數據,則使用數據庫查詢獲取記錄集。
- echo "n".str_pad('Read datas from MySQL.', 60, '_')."n";
- $conn = mysql_connect('localhost', 'test', 'test');
- mysql_select_db('test');
- $result = mysql_query($sql);
- while ($row = mysql_fetch_object($result))
- $datas[] = $row;
- // 將數據庫中獲取到的結果集數據保存到 memcached 中,以供下次訪問時使用。
- $mc->add($key, $datas);
- } else {
- echo "n".str_pad('Read datas from memcached.', 60, '_')."n";
- }
- var_dump($datas);
- ?>
頁面緩存:每次訪問頁面的時候,都會先檢測相應的緩存頁面文件是否存在,如果不存在,就連接數據庫,得到數據,顯示頁面并同時生成緩存頁面文件,這樣下次訪問的時候頁面文件就發揮作用了,模板引擎和網上常見的一些緩存類通常有此功能,代碼如下:
- <?php
- define('DIRECTORY_SEPARATOR','/');
- define('FOPEN_WRITE_CREATE_DESTRUCTIVE','wb');
- define('FOPEN_WRITE_CREATE','ab');
- define('DIR_WRITE_MODE', 0777);
- class FileCache {
- /**
- * 緩存路徑
- *
- * @access private
- * @var string
- */
- private $_cache_path;
- /**
- * 緩存過期時間,單位是秒second
- *
- * @access private
- * @var int
- */
- private $_cache_expire;
- /**
- * 解析函數,設置緩存過期實踐和存儲路徑
- *
- * @access public
- * @return void
- */
- public function __construct($expire, $cache_path)
- {
- $this->_cache_expire = $expire;
- $this->_cache_path = $cache_path;
- }
- /**
- * 緩存文件名
- *
- * @access public
- * @param string $key
- * @return void
- */
- private function _file($key)
- {
- return $this->_cache_path . md5($key);
- }
- /**
- * 設置緩存
- *
- * @access public
- * @param string $key 緩存的唯一鍵
- * @param string $data 緩存的內容
- * @return bool
- */
- public function set($key, $data)
- {
- $value = serialize($data);
- $file = $this->_file($key);
- return $this->write_file($file, $value);
- }
- /**
- * 獲取緩存
- *
- * @access public
- * @param string $key 緩存的唯一鍵
- * @return mixed
- */
- public function get($key)
- {
- $file = $this->_file($key);
- /** 文件不存在或目錄不可寫 */
- if (!file_exists($file) || !$this->is_really_writable($file))
- {
- return false;
- }
- /** 緩存沒有過期,仍然可用 */
- if ( time() < (filemtime($file) + $this->_cache_expire) )
- {
- $data = $this->read_file($file);
- if(FALSE !== $data)
- {
- return unserialize($data);
- }
- return FALSE;
- }
- /** 緩存過期,刪除之 */
- @unlink($file);
- return FALSE;
- }
- function read_file($file)
- {
- if ( ! file_exists($file))
- {
- return FALSE;
- }
- if (function_exists('file_get_contents'))
- {
- return file_get_contents($file);
- }
- if ( ! $fp = @fopen($file, FOPEN_READ))
- {
- return FALSE;
- }
- flock($fp, LOCK_SH);//讀取之前加上共享鎖
- $data = '';
- if (filesize($file) > 0)
- {
- $data =& fread($fp, filesize($file));
- }
- flock($fp, LOCK_UN);//釋放鎖
- fclose($fp);
- return $data;
- }
- function write_file($path, $data, $mode = FOPEN_WRITE_CREATE_DESTRUCTIVE)
- {
- if ( ! $fp = @fopen($path, $mode))
- {
- return FALSE;
- }
- flock($fp, LOCK_EX);
- fwrite($fp, $data);
- flock($fp, LOCK_UN);
- fclose($fp);
- return TRUE;
- }
- function is_really_writable($file)//兼容各平臺判斷文件是否有寫入權限
- {
- // If we're on a Unix server with safe_mode off we call is_writable
- if (DIRECTORY_SEPARATOR == '/' AND @ini_get("safe_mode") == FALSE)
- {
- return is_writable($file);
- }
- // For windows servers and safe_mode "on" installations we'll actually
- // write a file then read it. Bah...
- if (is_dir($file))
- {
- $file = rtrim($file, '/').'/'.md5(rand(1,100));
- if (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
- {
- return FALSE;
- }
- fclose($fp);
- @chmod($file, DIR_WRITE_MODE);
- @unlink($file);
- return TRUE;
- }
- elseif (($fp = @fopen($file, FOPEN_WRITE_CREATE)) === FALSE)
- {
- return FALSE;
- }
- fclose($fp);
- return TRUE;
- }
- }
- $cache = new FileCache(30,'cache/');
- $cache->set('test','this is a test.');
- print $cache->get('test');
- /* End of file FlieCache.php */
內存緩存:Memcached是高性能的,分布式的內存對象緩存系統,用于在動態應用中減少數據庫負載,提升訪問速度.
dbcached 是一款基于 Memcached 和 NMDB 的分布式 key-value 數據庫內存緩存系統.
以上的緩存技術雖然能很好的解決頻繁查詢數據庫的問題,但其缺點在在于數據無時效性,下面我給出我在項目中常用的方法,代碼如下:
- class MemcacheModel {
- private $mc = null;
- /**
- * 構造方法,用于添加服務器并創建memcahced對象
- */
- function __construct(){
- $params = func_get_args();
- $mc = new Memcache;
- //如果有多個memcache服務器
- if( count($params) > 1){
- foreach ($params as $v){
- call_user_func_array(array($mc, 'addServer'), $v);
- }
- //如果只有一個memcache服務器
- } else {
- call_user_func_array(array($mc, 'addServer'), $params[0]);
- }
- $this->mc=$mc;
- }
- /**
- * 獲取memcached對象
- * @return object memcached對象
- */
- function getMem(){
- return $this->mc;
- }
- /**
- * 檢查mem是否連接成功
- * @return bool 連接成功返回true,否則返回false
- */
- function mem_connect_error(){
- $stats=$this->mc->getStats();
- if(emptyempty($stats)){
- return false;
- }else{
- return true;
- }
- }
- private function addKey($tabName, $key){
- $keys=$this->mc->get($tabName);
- if(emptyempty($keys)){
- $keys=array();
- }
- //如果key不存在,就添加一個
- if(!in_array($key, $keys)) {
- $keys[]=$key; //將新的key添加到本表的keys中
- $this->mc->set($tabName, $keys, MEMCACHE_COMPRESSED, 0);
- return true; //不存在返回true
- }else{
- return false; //存在返回false
- }
- }
- /**
- * 向memcache中添加數據
- * @param string $tabName 需要緩存數據表的表名
- * @param string $sql 使用sql作為memcache的key
- * @param mixed $data 需要緩存的數據
- */
- function addCache($tabName, $sql, $data){
- $key=md5($sql);
- //如果不存在
- if($this->addKey($tabName, $key)){
- $this->mc->set($key, $data, MEMCACHE_COMPRESSED, 0);
- }
- }
- /**
- * 獲取memcahce中保存的數據
- * @param string $sql 使用SQL的key
- * @return mixed 返回緩存中的數據
- */
- function getCache($sql){
- $key=md5($sql);
- return $this->mc->get($key);
- }
- /**
- * 刪除和同一個表相關的所有緩存
- * @param string $tabName 數據表的表名
- */
- function delCache($tabName){
- $keys=$this->mc->get($tabName);
- //刪除同一個表的所有緩存
- if(!emptyempty($keys)){
- foreach($keys as $key){
- $this->mc->delete($key, 0); //0 表示立刻刪除
- }
- }
- //刪除表的所有sql的key
- $this->mc->delete($tabName, 0);
- }
- /**
- * 刪除單獨一個語句的緩存
- * @param string $sql 執行的SQL語句
- */
- function delone($sql){
- $key=md5($sql);
- $this->mc->delete($key, 0); //0 表示立刻刪除
- }
- }
時間觸發緩存:檢查文件是否存在并且時間戳小于設置的過期時間,如果文件修改的時間戳比當前時間戳減去過期時間戳大,那么就用緩存,否則更新緩存.
設定時間內不去判斷數據是否要更新,過了設定時間再更新緩存,以上只適合對時效性要求不高的情況下使用,否則請看下面.
內容觸發緩存:當插入數據或更新數據時,強制更新緩存.
在這里我們可以看到,當有大量數據頻繁需要更新時,最后都要涉及磁盤讀寫操作,怎么解決呢?我在日常項目中,通常并不緩存所有內容,而是緩存一部分不經常變的內容來解決,但在大負荷的情況下,最好要用共享內存做緩存系統.
到這里PHP緩存也許有點解決方案了,但其缺點是,因為每次請求仍然要經過PHP解析,在大負荷的情況下效率問題還是比效嚴重,在這種情況下,也許會用到靜態緩存.
靜態緩存:這里所說的靜態緩存是指HTML緩存,HTML緩存一般是無需判斷數據是否要更新的,因為通常在使用HTML的場合一般是不經常變動內容的頁面,數據更新的時候把HTML也強制更新一下就可以了.
也有像thinkphp的靜態緩存,ThinkPHP官方手冊寫道靜態規則的定義有三種方式,代碼如下:
- Return Array(
- ‘ActionName’=>array(‘靜態規則’,’靜態緩存有效期’,’附加規則’), //第一種
- ‘ModuleName:ActionName’=>array(‘靜態規則’,’靜態緩存有效期’,’附加規則’),//第二種
- ‘*’=>array(‘靜態規則’,’靜態緩存有效期’,’附加規則’),//第三種
- …更多操作的靜態規則
- )
第一種是定義全局的操作靜態規則,例如定義所有的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緩存,代碼如下:
- <?php
- require('./smarty/Smarty.class.php');
- $smarty = new Smarty;
- $smarty->caching = true;
- if(!$smarty->is_cached('index.tpl')) {
- // No cache available, do variable assignments here.
- $contents = get_database_contents();
- $smarty->assign($contents);
- }
- $smarty->display('index.tpl');
- ?>
新聞熱點
疑難解答