轉載地址 http://justcoding.iteye.com/blog/650010
在大部份情況下我們的網站都會使用數據庫作爲站點數據存儲的容器。當你執行一個SQL查詢時,典型的處理過程 是:連接數據庫->準備SQL查詢->發送查詢到數據庫->取得數據庫返回結果->關閉數據庫連接。但數據庫中有些數據是完全靜 態的或不太經常變動的,緩存系統會通過把SQL查詢的結果緩存到一個更快的存儲系統中存儲,從而避免頻繁操作數據庫而很大程度上提高了程序執行時間,而且 緩存查詢結果也允許你後期處理。
普遍使用的緩 存技術
數據緩存:這裏所說的數據緩存是指數據庫查詢緩存,每次訪問頁面的時候,都會先檢測相應的緩存數據是否存 在,如果不存在,就連接數據庫,得到數據,並把查詢結果序列化後保存到文件中,以後同樣的查詢結果就直接從緩存文件中獲得。
頁面緩存:
每次訪問頁面的時候,都會先檢測相應的緩存頁面文件是否存在,如果不存在,就連接數據庫,得到數據,顯示 頁面並同時生成緩存頁面文件,這樣下次訪問的時候頁面文件就發揮作用了。(模板引擎和網上常見的一些緩存類通常有此功能)
內存緩存:
在裏就不介紹了,不是本文所要討論的,只簡單提一下:
Memcached是高性能的,分佈式的內存對象緩存系統,用於在動態應用中減少數據庫負載,提升訪問速 度。
dbcached 是一款基於 Memcached 和 NMDB 的分佈式 key-value 數據庫內存緩存系統。
以上的緩存技術雖然能很好的解決頻繁查詢數據庫的問題,但其缺點在在於數據無時效性,下面我給出我在項目 中常用的方法:
時間觸發緩 存:
檢查文件是否存在並且時間戳小於設置的過期時間,如果文件修改的時間戳比當前時間戳減去過期時間戳大,那 麼就用緩存,否則更新緩存。
設定時間內不去判斷數據是否要更新,過了設定時間再更新緩存。以上只適合對時效性要求不高的情況下使用 ,否則請看下面。
內容觸發緩 存:
當插入數據或更新數據時,強制更新緩存。
在這裏我們可以看到,當有大量數據頻繁需要更新時,最後都要涉及磁盤讀寫操作。怎麼解決呢?我在日常項目 中,通常並不緩存所有內容,而是緩存一部分不經常變的內容來解決。但在大負荷的情況下,最好要用共享內存做緩存系統。
到這裏PHP緩存也許有點解決方案了,但其缺點是,因爲每次請求仍然要經過PHP解析,在大負荷的情況下 效率問題還是比效嚴重,在這種情況下,也許會用到靜態緩存。
靜態緩存
這裏所說的靜態緩存是指HTML緩存,HTML緩存一般是無需判斷數據是否要更新的,因爲通常在使用 HTML的場合一般是不經常變動內容的頁面。數據更新的時候把HTML也強制更新一下就可以了。
實例1:
- <?php
- /*
- 實 例:
- include("cache.php");
- $cache = new cache(30);
- $cache->cacheCheck();
- echo date("Y-m-d H:i:s");
- $cache->caching();
- */
- class cache {
- // 緩存目錄
- var $cacheRoot = "./cache/";
- //緩存更新時間秒數,0爲不緩存
- var $cacheLimitTime = 0;
- //緩存文件名
- var $cacheFileName = "";
- //緩存擴展名
- var $cacheFileExt = "php";
- /*
- * 構造函數
- * int $cacheLimitTime 緩存更新時間
- */
- function cache( $cacheLimitTime ) {
- if( intval( $cacheLimitTime ) )
- $this->cacheLimitTime = $cacheLimitTime;
- $this->cacheFileName = $this->getCacheFileName();
- ob_start();
- }
- /*
- * 檢查緩存文件是否在設置更新時間之內
- * 返回:如果在更新時間之內則返回文件內容,反之則返回失敗
- */
- function cacheCheck(){
- if( file_exists( $this->cacheFileName ) ) {
- $cTime = $this->getFileCreateTime( $this->cacheFileName );
- if( $cTime + $this->cacheLimitTime > time() ) {
- echo file_get_contents( $this->cacheFileName );
- ob_end_flush();
- exit;
- }
- }
- return false;
- }
- /*
- * 緩存文件或者輸出靜態
- * string $staticFileName 靜態文件名(含相對路徑)
- */
- function caching( $staticFileName = "" ){
- if( $this->cacheFileName ) {
- $cacheContent = ob_get_contents();
- //echo $cacheContent;
- ob_end_flush();
- if( $staticFileName ) {
- $this->saveFile( $staticFileName, $cacheContent );
- }
- if( $this->cacheLimitTime )
- $this->saveFile( $this->cacheFileName, $cacheContent );
- }
- }
- /*
- * 清除緩存文件
- * string $fileName 指定文件名(含函數)或者all(全部)
- * 返回:清除成功返回true,反之返回false
- */
- function clearCache( $fileName = "all" ) {
- if( $fileName != "all" ) {
- $fileName = $this->cacheRoot . strtoupper(md5($fileName)).".".$this->cacheFileExt;
- if( file_exists( $fileName ) ) {
- return @unlink( $fileName );
- }else return false;
- }
- if ( is_dir( $this->cacheRoot ) ) {
- if ( $dir = @opendir( $this->cacheRoot ) ) {
- while ( $file = @readdir( $dir ) ) {
- $check = is_dir( $file );
- if ( !$check )
- @unlink( $this->cacheRoot . $file );
- }
- @closedir( $dir );
- return true;
- }else{
- return false;
- }
- }else{
- return false;
- }
- }
- /*
- * 根據當前動態文件生成緩存文件名
- */
- function getCacheFileName() {
- return $this->cacheRoot . strtoupper(md5($_SERVER["REQUEST_URI"])).".".$this->cacheFileExt;
- }
- /*
- * 緩存文件建立時間
- * string $fileName 緩存文件名(含相對路徑)
- * 返回:文件生成時間秒數,文件不存在返回0
- */
- function getFileCreateTime( $fileName ) {
- if( ! trim($fileName) ) return 0;
- if( file_exists( $fileName ) ) {
- return intval(filemtime( $fileName ));
- }else return 0;
- }
- /*
- * 保存文件
- * string $fileName 文件名(含相對路徑)
- * string $text 文件內容
- * 返回:成功返回ture,失敗返回false
- */
- function saveFile($fileName, $text) {
- if( ! $fileName || ! $text ) return false;
- if( $this->makeDir( dirname( $fileName ) ) ) {
- if( $fp = fopen( $fileName, "w" ) ) {
- if( @fwrite( $fp, $text ) ) {
- fclose($fp);
- return true;
- }else {
- fclose($fp);
- return false;
- }
- }
- }
- return false;
- }
- /*
- * 連續建目錄
- * string $dir 目錄字符串
- * int $mode 權限數字
- * 返回:順利創建或者全部已建返回true,其它方式返回false
- */
- function makeDir( $dir, $mode = "0777" ) {
- if( ! $dir ) return 0;
- $dir = str_replace( "\\", "/", $dir );
- $mdir = "";
- foreach( explode( "/", $dir ) as $val ) {
- $mdir .= $val."/";
- if( $val == ".." || $val == "." || trim( $val ) == "" ) continue;
- if( ! file_exists( $mdir ) ) {
- if(!@mkdir( $mdir, $mode )){
- return false;
- }
- }
- }
- return true;
- }
- }
- $cache = new cache(30);
- $cache->cacheCheck();
- echo date("Y-m-d H:i:s");
- $cache->caching();
- ?>
實例2: 數據緩存
- <?php
- class Cache {
- private $dir = 'cache';
- private $expiration = 3600;
- function __construct($dir = '')
- {
- if(!emptyempty($dir)){ $this->dir = $dir; }
- }
- private function _name($key)
- {
- return sprintf("%s/%s", $this->dir, sha1($key));
- }
- public function get($key, $expiration = '')
- {
- if ( !is_dir($this->dir) OR !is_writable($this->dir))
- {
- return FALSE;
- }
- $cache_path = $this->_name($key);
- if (!@file_exists($cache_path))
- {
- return FALSE;
- }
- $expiration = emptyempty($expiration) ? $this->expiration : $expiration;
- if (filemtime($cache_path) < (time() - $expiration))
- {
- $this->clear($key);
- return FALSE;
- }
- if (!$fp = @fopen($cache_path, 'rb'))
- {
- return FALSE;
- }
- flock($fp, LOCK_SH);
- $cache = '';
- if (filesize($cache_path) > 0)
- {
- $cache = unserialize(fread($fp, filesize($cache_path)));
- }
- else
- {
- $cache = NULL;
- }
- flock($fp, LOCK_UN);
- fclose($fp);
- return $cache;
- }
- public function set($key, $data)
- {
- if ( !is_dir($this->dir) OR !is_writable($this->dir))
- {
- $this->_makeDir($this->dir);
- }
- $cache_path = $this->_name($key);
- if ( ! $fp = fopen($cache_path, 'wb'))
- {
- return FALSE;
- }
- if (flock($fp, LOCK_EX))
- {
- fwrite($fp, serialize($data));
- flock($fp, LOCK_UN);
- }
- else
- {
- return FALSE;
- }
- fclose($fp);
- @chmod($cache_path, 0777);
- return TRUE;
- }
- public function clear($key)
- {
- $cache_path = $this->_name($key);
- if (file_exists($cache_path))
- {
- unlink($cache_path);
- return TRUE;
- }
- return FALSE;
- }
- public function clearAll()
- {
- $dir = $this->dir;
- if (is_dir($dir))
- {
- $dh=opendir($dir);
- while (false !== ( $file = readdir ($dh)))
- {
- if($file!="." && $file!="..")
- {
- $fullpath=$dir."/".$file;
- if(!is_dir($fullpath)) {
- unlink($fullpath);
- } else {
- delfile($fullpath);
- }
- }
- }
- closedir($dh);
- // rmdir($dir);
- }
- }
- private function _makeDir( $dir, $mode = "0777" ) {
- if( ! $dir ) return 0;
- $dir = str_replace( "\\", "/", $dir );
- $mdir = "";
- foreach( explode( "/", $dir ) as $val ) {
- $mdir .= $val."/";
- if( $val == ".." || $val == "." || trim( $val ) == "" ) continue;
- if( ! file_exists( $mdir ) ) {
- if(!@mkdir( $mdir, $mode )){
- return false;
- }
- }
- }
- return true;
- }
- }
例子:
- <?
- require_once('cache.php');
- $cache = new Cache();
- $data = $cache->get('key');
- if ($data === FALSE)
- {
- $data = 'This will be cached';
- $cache->set('key', $data);
- echo $data.'--first time';
- }
- echo $data;
- //$cache->clearAll();
- //$cache->clear('key');
- //Do something with $data
另一個數據緩存:
- <?php
- class file_cache
- {
- private $root_dir;
- public function __construct ($root_dir)
- {
- $this->root_dir = $root_dir;
- if (FALSE == file_exists($this->root_dir))
- {
- mkdir($this->root_dir, 0700, true);
- }
- }
- public function set ($key, $value)
- {
- $key = $this->escape_key($key);
- $file_name = $this->root_dir . '/' . $key;
- $dir = dirname($file_name);
- if (FALSE == file_exists($dir))
- {
- mkdir($dir, 0700, true);
- }
- file_put_contents($file_name, serialize($value), LOCK_EX);
- }
- public function get ($key)
- {
- $key = $this->escape_key($key);
- $file_name = $this->root_dir . '/' . $key;
- if (file_exists($file_name))
- {
- return unserialize(file_get_contents($file_name));
- }
- return null;
- }
- public function remove ($key)
- {
- $key = $this->escape_key($key);
- $file = $this->root_dir . '/' . $key;
- if (file_exists($file))
- {
- unlink($file);
- }
- }
- public function remove_by_search ($key)
- {
- $key = $this->escape_key($key);
- $dir = $this->root_dir . '/' . $key;
- if (strrpos($key, '/') < 0)
- $key .= '/';
- if (file_exists($dir))
- {
- $this->removeDir($dir);
- }
- }
- private function escape_key ($key)
- {
- return str_replace('..', '', $key);
- }
- function removeDir($dirName)
- {
- $result = false;
- $handle = opendir($dirName);
- while(($file = readdir($handle)) !== false)
- {
- if($file != '.' && $file != '..')
- {
- $dir = $dirName . DIRECTORY_SEPARATOR . $file;
- is_dir($dir) ? $this->removeDir($dir) : unlink($dir);
- }
- }
- closedir($handle);
- rmdir($dirName) ? true : false;
- return $result;
- }
- }
- $data_1 = array(
- 'u_id' => 1,
- 'name' => '利沙'
- );
- $data_2 = array(
- 'u_id' => 2,
- 'name' => 'WaWa'
- );
- $cache = new file_cache("test");
- $cache->set("user/1/data", $data_1); //保存數據
- $cache->set("user/2/data", $data_2); //保存數據
- $result = $cache->get("user/1/data"); //獲取數據
- echo '測試如下:<pre>';
- print_r($result);
- //$cache->remove("user/1/data"); //刪除數據
- //$cache->remove_by_search("user", $data_1); //刪除user節點下所有數據