国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 > php教程 > php手冊 > 正文

緩存的使用,緩存使用

php中文網(wǎng)
發(fā)布: 2016-06-13 09:16:10
原創(chuàng)
933人瀏覽過

緩存的使用,緩存使用

  緩存,提高訪問速度的利器。工作中主要用到的是memcache和redis,它們是b/s軟件,類似練習(xí)時裝在機子上的apache,它也會監(jiān)聽端口,可以在客戶端(如在cmd上通過telnet操作memcache)直接敲各自對應(yīng)的命令來存取值,自學(xué)時可以通過這樣的方式熟悉下原生命令,看看效果。它們常駐內(nèi)存,得到數(shù)據(jù)后寫入內(nèi)存(安裝軟件后會占用一片內(nèi)存區(qū)域),設(shè)定數(shù)據(jù)的過期時間,用到時直接從內(nèi)存中讀出來,因為是內(nèi)存所以訪問速度上有數(shù)量級的提高。lz曾今寫了個非常簡單的后臺,完全不用緩存那種,那速度我自己看了都忍不住要咆哮:這么慢tm也能叫網(wǎng)頁?!可那時我年幼無知,不會用緩存,當(dāng)然現(xiàn)在也不見得好到哪兒去,但愿那時前端妹子沒在心里暗自唾罵>3<......>

  memcache的使用較簡單,至少從命令上來看是這樣。在memcache中,存儲的方式是key->value,鍵-值對應(yīng)的方式存儲,類似聯(lián)接數(shù)組的元素形式,可存儲的類型可以是數(shù)字、字符串、數(shù)組、對象等,項目中一般會將非字符串(數(shù)字可看成是數(shù)字字符串)類型的先進行json編碼或者序列化再存入緩存,取出來時則解碼或者反序列化。Memcache是php專門處理memcache緩存的類,封裝的主要方法是get、set、delete、flush、connect、close,即一個緩存必備的獲取、設(shè)置、刪除、清空、連接、關(guān)閉等。(中括號為可傳參數(shù))

add key, var, [flag], [expire] 添加一個鍵為key、值為var到服務(wù)端,可指定過期時間expire,0則永不過期,最長30天
get key, [flag] 從服務(wù)端獲取某一或某些元素
delete key, [timeout] 在指定timeout時間內(nèi)刪除key對應(yīng)元素,默認(rèn)timeout為0立即刪除
flush 清空,即刪除所有元素
connect host, [port], [timeout] 連接到memcache服務(wù)器host主機的port端口,它會在腳本執(zhí)行完自動關(guān)閉,也可主動關(guān)閉
close 主動關(guān)閉memcache服務(wù)端連接,但不會關(guān)閉pconnect生成的連接
set key, var, [flag], [expire] 存儲鍵為key、值為var的元素到服務(wù)端,key存在則覆蓋其值,不存在新add一個
replace key, var, [flag], [expire] 查找鍵為key的元素,以值var替換,查不到會報錯
increment key, [value] 在鍵為key的元素上增加值value,value默認(rèn)為1,可能改變原值
decrement key, [value] 在鍵為key的元素上減少值value,value默認(rèn)為1,可能改變原值
addServer host, [port], [persistent], [weight], [timeout], ...... 添加一個memcache服務(wù)到連接池(保存多個memcache連接的地方)中,即建立一個到host的連接,port為端口
pconnect host, [port], [timeout] 建立到位于host主機的memcache服務(wù)器的持久連接,port為端口,腳本執(zhí)行完或調(diào)用close也無法關(guān)閉這種連接

  其中有幾點需要留意下:

  1. set和replace的用法區(qū)別:set幾乎任何情況下,當(dāng)然不是連接都失敗、內(nèi)存不夠用等硬性原因,都是成功的,replace只是在已經(jīng)存在的鍵的基礎(chǔ)上進行修改,鍵若不存在不成功;

  2. connect方法建立的連接,要么腳本運行結(jié)束自己斷開,要么調(diào)用close()方法被斷開掉;

  3. increment或者的decrement方法得到的數(shù)永遠(yuǎn)是大于或等于0,如果確實計算后得到的值是小于0的則進行轉(zhuǎn)化,比如int類型,32位上占4字節(jié),則返回的值是(232-1),計算后大于或等于0的直接返回;而元素之類型為非數(shù)字(或數(shù)字字符串)的,先轉(zhuǎn)為數(shù)字再計算;

  4. 當(dāng)我們new一個Memcache對象并進行連接時,可以有兩種方式,一是connect方法:$mem =new Memcache; $mem->connect('127.0.0.1', 11211); 或者使用addserver方法:$mem->addServer('127.0.0.1', 11211); 后者以向已有的連接池中添加一個Memcache服務(wù)器連接的方式建立,效果一樣。

  Redis,一款強大的緩存工具,得益于在國內(nèi)門戶網(wǎng)站中的廣泛使用,功能上在不斷完善,現(xiàn)在有穩(wěn)定的版本(貌似微軟github上最新64位的release 2.8版本,在我工作的機子上運行不起來...),方法比memcache多得多,作為開發(fā)使用到的主要是數(shù)據(jù)的存取,而其他的事物、通信協(xié)議、集群,在一般開發(fā)個后臺,不是對速度追求到極致的情況下,還是基本用不到。redis中有按操作分為以下幾種類型:

  1. String:也是key-value對,主要也是對它的鍵對應(yīng)的元素進行g(shù)et、set、求長度、自增等操作,redis將添加的類型全存為字符串,即便純數(shù)字;

  

  2. Hash:哈希表(散列表),就是數(shù)據(jù)結(jié)構(gòu)中的字典,采用特定的散列算法,比如手機通訊錄有幾百人,以姓的第一個字母作為關(guān)鍵碼進行排序,這樣我們可以快速找到聯(lián)系人,這是通過特定的映射方式,將一個字母與姓名聯(lián)系起來。在redis中,創(chuàng)建hash表時,首先指定表名,你存在哪張表里邊,然后指定一個域(field,實際就是一個變量),和它對應(yīng)的值,單用cmd操作就像下面這樣(在hash表hash1中存儲一個域username對應(yīng)值Jack,redis會自動建立username到Jack的映射),一張hash表里邊可以存儲多個域和對應(yīng)的變量;

  

  3. List:列表,類似于相當(dāng)于數(shù)據(jù)結(jié)構(gòu)的鏈表,通過它還可實現(xiàn)棧和隊列,前面的string(這名字取得很怪異)存儲一一對應(yīng)的單個鍵值對,它則存多個值(沒有鍵),重點是作為一個列表結(jié)構(gòu),它可以分別從左右(表頭和表尾)進行插入和彈出變量值,求長度等一系列操作,這也是為什么稱為列表,下面lpush、rpush命令就是從表左邊和右邊插入變量hello和world;

  

  4. Set:集合,顧名思義也可以存儲多個變量值(沒有鍵),只是符合數(shù)學(xué)上定義的集合的特性,比如集合中元素不重復(fù),因此set中各個數(shù)據(jù)對的鍵名也不一樣,它也可以進行并、交、差等運算(下面命令是向集合mySet添加一個值var);

  

? ? ?5. SortedSet:有序集合,可看做Set的特殊方式,在每一個SortedSet類型集合中,添加一個值(沒有鍵)時,都要給它們指定一個稱為score的變量值,有序有序,得有個字段來判定它的順序是不,就是這個玩意兒,下面命令創(chuàng)建一個有序集合stset,添加一個值google.com,它的score是10。其實猜也猜得到,既然叫有序集合,既然給定了score,基本確定可以用這個來進行某些排序操作,事實也是這樣;

  

  6. Key:單獨對鍵進行操作,當(dāng)然對其對應(yīng)的元素值也有影響,如查看鍵對應(yīng)元素的數(shù)據(jù)類型、鍵對應(yīng)元素的存活時間、重置存活時間、返回所有鍵、正則形式查看相關(guān)鍵名、刪除鍵(元素也跟著沒了)等等。它不是數(shù)據(jù)類型,實際上,Redis把Hash表表名、List列表表名、集合Set名都稱為鍵,整個集合或者表是它的值。下面是type命令查看它存儲值得類型,它存儲的是List列表。

  

  上面這些命令,找個參考文檔走一遍,很快就能玩熟,個人在這兒也只是泛泛而談。那么在實際項目中,通常是怎樣使用緩存呢?不往大的談,比如微博的緩存設(shè)計,這可能涉及到架構(gòu)層面的東西了,單說作為一個有一定訪問量的后臺,又想使用緩存來提高速度的情況下。

  一個重要的原則(個人目前碰得多的情況)是,以傳入的參數(shù)來拼鍵名,以這個鍵名來存取值。比如現(xiàn)在Model模型類里面有個方法:getUserInfoByUid($params),傳入包含uid字段的數(shù)組查詢這個用戶的信息,在這兒使用緩存,先取緩存數(shù)據(jù),取不到則去查數(shù)據(jù)庫,然后重新加入緩存,最后返回結(jié)果數(shù)據(jù),這也是使用緩存的一個通用流程。

  以Memcache為例,先看代碼,定義一個Cache類:

    <span>/*</span><span>*
     * Memcache緩存類
     </span><span>*/</span>
    <span>define</span>('CACHE_HOST', '127.0.0.1'<span>);
    </span><span>define</span>('CACHE_PORT', 11211<span>);
    
    </span><span>class</span><span> Cache{
        </span><span>private</span> <span>static</span> <span>$instance</span> = <span>null</span><span>;  
        
        </span><span>private</span> <span>$_cache</span> = <span>null</span>;  <span>//</span><span> 緩存操作對象</span>
        
        <span>const</span> prefix = 'APP|';  <span>//</span><span> 緩存鍵值的前綴,為該項目名稱 </span>
        
        <span>private</span> <span>function</span><span> __construct(){
            </span><span>if</span>(<span>$this</span>->_cache === <span>null</span><span>){
                </span><span>try</span><span>{
                    </span><span>$this</span>->_cache = <span>new</span><span> Memcache;
                    </span><span>if</span>(!<span>$this</span>->_cache->connect(CACHE_HOST,<span> CACHE_PORT)){
                        </span><span>exit</span>('connect failed'<span>);
                    }
                    
                }
                </span><span>catch</span>(<span>Exception</span> <span>$e</span><span>){
                    </span><span>echo</span> 'ERROR: '.<span>$e</span>-><span>getMessage();
                }
                
            }
        }
        </span><span>/*</span><span>* 
         * 返回單例
         </span><span>*/</span>
        <span>public</span> <span>static</span> <span>function</span><span> getInstance(){
            </span><span>if</span>(self::<span>$instance</span> === <span>null</span><span>){
                self</span>::<span>$instance</span> = <span>new</span><span> self();
            }
            </span><span>return</span> self::<span>$instance</span><span>;
        }
        </span><span>/*</span><span>*
         * 生成鍵名
         </span><span>*/</span>
        <span>private</span> <span>function</span> genKey(<span>$key</span><span>){
            </span><span>return</span> Cache::prefix.<span>$key</span><span>;
        }
        
        </span><span>public</span> <span>function</span><span> __destruct(){
            </span><span>if</span>(<span>$this</span>->_cache !== <span>null</span><span>){
                </span><span>return</span> <span>$this</span>->_cache-><span>close();
            }
        }
        </span><span>/*</span><span>*
         * 添加元素,設(shè)置過期時間
         </span><span>*/</span>
        <span>public</span> <span>function</span> add(<span>$key</span>, <span>$val</span>, <span>$expire</span> = 3600<span>){
            </span><span>return</span> <span>$this</span>->_cache->add(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span>, 0, <span>$expire</span><span>);
        }
        </span><span>/*</span><span>*
         * 重置元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> set(<span>$key</span>, <span>$val</span>, <span>$expire</span> = 3600<span>){
            </span><span>echo</span> 'cache key: '.<span>$this</span>->genKey(<span>$key</span>).'<br/>';  <span>//</span><span> test</span>
            <span>return</span> <span>$this</span>->_cache->set(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span>, 0, <span>$expire</span><span>);
        }
        </span><span>/*</span><span>*
         * 獲取元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> get(<span>$key</span><span>){
            </span><span>return</span> <span>$this</span>->_cache->get(<span>$this</span>->genKey(<span>$key</span><span>));
        }
        </span><span>/*</span><span>*
         * 自增
         </span><span>*/</span>
        <span>public</span> <span>function</span> increment(<span>$key</span>, <span>$val</span> = 1<span>){
            </span><span>return</span> <span>$this</span>->_cache->increment(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span><span>);
        }
        </span><span>/*</span><span>*
         * 自減
         </span><span>*/</span>
        <span>public</span> <span>function</span> decrement(<span>$key</span>, <span>$val</span> = 1<span>){
            </span><span>return</span> <span>$this</span>->_cache->decrement(<span>$this</span>->genKey(<span>$key</span>), <span>$val</span><span>);
        }
        </span><span>/*</span><span>*
         * 刪除元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> delete(<span>$key</span>, <span>$timeout</span> = 0<span>){
            </span><span>return</span> <span>$this</span>->_cache->delete(<span>$this</span>->genKey(<span>$key</span>), <span>$timeout</span><span>);
        }
        </span><span>/*</span><span>*
         * 刪除所有元素
         </span><span>*/</span>
        <span>public</span> <span>function</span> <span>flush</span><span>(){
            </span><span>return</span> <span>$this</span>->_cache-><span>flush</span><span>();
        }    
    }</span>
登錄后復(fù)制

?  然后定義一個操作數(shù)據(jù)庫操作類:

    <span>/*</span><span>*
     * 數(shù)據(jù)庫操作
     </span><span>*/</span>
    <span>define</span>('DB_NAME', 'test'<span>);
    </span><span>define</span>('DB_HOST', '127.0.0.1'<span>);
    </span><span>define</span>('DB_PORT', 3306<span>);
    </span><span>define</span>('DB_USER', 'root'<span>);
    </span><span>define</span>('DB_PASS', '1234'<span>);
    
    </span><span>class</span><span> Dal{
        </span><span>private</span> <span>static</span> <span>$instance</span> = <span>null</span><span>;
        
        </span><span>public</span> <span>$pdo</span> = <span>null</span><span>;        
        
        </span><span>private</span> <span>function</span><span> __construct(){
            </span><span>try</span><span>{
                </span><span>$dsn</span> = 'mysql:dbname='.DB_NAME.';host='.DB_HOST.':'.<span>DB_PORT;
                </span><span>$this</span>->pdo = <span>new</span> PDO(<span>$dsn</span>, DB_USER,<span> DB_PASS);
            }
            </span><span>catch</span>(PDOException <span>$e</span><span>){
                </span><span>echo</span> 'Error: '.<span>$e</span>-><span>getMessage();
                </span><span>return</span> <span>false</span><span>;
            }
        }
        </span><span>//</span><span>獲取實例</span>
        <span>public</span> <span>static</span> <span>function</span><span> getInstance(){
            </span><span>if</span>(self::<span>$instance</span> === <span>null</span><span>){
                self</span>::<span>$instance</span> = <span>new</span><span> self();
            }
            </span><span>return</span> self::<span>$instance</span><span>;
        }
        </span><span>//</span><span> 獲取用戶信息</span>
        <span>public</span> <span>function</span> getUserInfoByUid(<span>$uid</span><span>){
            </span><span>$sql</span> = <span>sprintf</span>('select * from tab1 where uid = %s limit 1', <span>$uid</span><span>);
            </span><span>$stmt</span> = <span>$this</span>->pdo->query(<span>$sql</span><span>);
            </span><span>return</span> <span>$stmt</span>->fetch(PDO::<span>FETCH_ASSOC);
        }
    }</span>
登錄后復(fù)制

  而一般來說,通常是在Model模型類中才對數(shù)據(jù)進行讀寫,因此再定義一個UserModel類,盡量從簡,不再去寫可能會有的Model公共公共基類。

    <span>include</span> 'Dal.php'<span>;
    </span><span>include</span> 'Cache.php'<span>;
    
    </span><span>class</span><span> UserModel{
        </span><span>private</span> <span>static</span> <span>$instance</span> = <span>null</span><span>;
        
        </span><span>public</span> <span>$cache</span> = <span>null</span><span>;
        
        </span><span>public</span> <span>$db</span> = <span>null</span><span>;
        
        </span><span>//</span><span> 緩存鍵名部分,通過函數(shù)名稱及參數(shù)拼接</span>
        <span>const</span> cache_get_userinfo_uid = 'GET|USER|INFO|BY|UID|%s'<span>;
        
        </span><span>private</span> <span>function</span><span> __construct(){
            </span><span>//</span><span> 獲取對應(yīng)類實例</span>
            <span>$this</span>->cache = Cache::<span>getInstance();
            </span><span>$this</span>->db = Dal::<span>getInstance();
        }
        
        </span><span>public</span> <span>static</span> <span>function</span><span> getInstance(){
            </span><span>if</span>(self::<span>$instance</span> === <span>null</span><span>){
                self</span>::<span>$instance</span> = <span>new</span><span> self();
            }
            </span><span>return</span> self::<span>$instance</span><span>;
        }
        
        </span><span>/*</span><span>*
         根據(jù)uid獲取用戶信息
         </span><span>*/</span>
        <span>public</span> <span>function</span> getUserInfoByUid(<span>$params</span>, <span>$timeout</span> = 3600<span>){
            </span><span>//</span><span> 缺少必要參數(shù)uid,返回</span>
            <span>if</span>(<span>empty</span>(<span>$params</span>['uid'<span>])){
                </span><span>return</span> <span>null</span><span>;
            }
    
            </span><span>//</span><span> 拼接緩存鍵名</span>
            <span>$key</span> = <span>sprintf</span>(self::cache_get_userinfo_uid, <span>$params</span>['uid'<span>]);
                    
            </span><span>//</span><span> 獲取緩存數(shù)據(jù)</span>
            <span>$data</span> = json_decode(<span>$this</span>->cache->get(<span>$key</span>), <span>true</span><span>);
            
            </span><span>echo</span> 'cache=><pre class="brush:php;toolbar:false">'<span>;
            </span><span>var_dump</span>(<span>$data</span><span>);
            
            </span><span>//</span><span> 緩存為空</span>
            <span>if</span>(!<span>$data</span><span>){
                </span><span>$data</span> = <span>$this</span>->db->getUserInfoByUid(<span>$params</span>['uid'<span>]);
                </span><span>if</span>(<span>empty</span>(<span>$data</span><span>)){
                    </span><span>return</span> <span>null</span><span>;
                }
                </span><span>//</span><span> 在數(shù)據(jù)庫中獲取到數(shù)據(jù)后,重新寫入緩存</span>
                <span>$this</span>->cache->set(<span>$key</span>, json_encode(<span>$data</span>), <span>$timeout</span><span>);
            }
            </span><span>else</span><span>{
                
            }
            </span><span>return</span> <span>$data</span><span>;
        }
    }
    </span><span>//</span><span> 測試</span>
    <span>$data</span> = UserModel::getInstance()->getUserInfoByUid(<span>array</span>('uid'=>17653), 5<span>);
    </span><span>echo</span> 'UserModel=><pre class="brush:php;toolbar:false">'<span>;
    </span><span>var_dump</span>(<span>$data</span>);
登錄后復(fù)制

  這里,我們要通過用戶的uid獲取一個用戶的信息,這個查詢條件是uid,傳過來的必要參數(shù)是uid,本來我們就是要緩存每個用戶的數(shù)據(jù),以期在重復(fù)查詢時速度更快,因此在定義緩存的鍵時,就可以考慮使用uid。但是單單使用這個uid不行,因為假如其他的表中也有根據(jù)uid查詢的,就會出現(xiàn)鍵名重復(fù),造成了數(shù)據(jù)混亂,好我們使用的是getUserInfoByUid這個方法,可以把方法名也拼進去,因此在UserModel類中,定義了一個常量cache_get_userinfo_uid,它最后的%s就是為了拼接參數(shù)uid。但是,這樣可能還是不行,現(xiàn)在公司啟動了另外一個項目,也要用到這個表,某人寫的方法跟這個方法名完全一樣,畢竟函數(shù)名字又沒有專利,而且運維一般單獨拿服務(wù)器出來作為緩存使用,幾個項目公用一臺服務(wù)器,數(shù)據(jù)寫在一個緩存池里也正常,此時可以考慮再加個前綴---工程名稱(或說項目),因此,在Cache類中,又定義了一個常量prefix,給這個項目叫APP,這樣基本就可以保證不會沖突了。當(dāng)然如果這是一個組的子項目,這個組還有其他項目,這個組叫Star的話,可以再將項目組名稱加在前面。

  看看效果,第一次(左邊)運行讀取cache是空的,但是可以看到打印的緩存鍵名,

  ? ? ? ? ?

  第二次(右邊)cache就有數(shù)據(jù)了,因為我把打印緩存鍵名的地方放在Cache類的set方法中,第二次直接讀到了緩存數(shù)據(jù),沒有去連數(shù)據(jù)庫,自然也沒有重置緩存,所以沒打印cache key。

  扯了半天就是要保證鍵名不沖突,也夾雜了一般在一個項目中怎樣使用緩存,有幾個供參考的方式:

  1. 當(dāng)前參數(shù),可以有幾個拼接幾個,這里只舉了個uid,假如還有name, age等等,可以都放在后面,具體怎么弄看個人喜好或者代碼規(guī)范;

  2. 當(dāng)前方法名稱,盡量接近當(dāng)前方法名稱,拼在緩存key中間;

  3. 當(dāng)前項目名稱作為前綴(可選),更安全;

  4. 所在項目組名稱,再次作為前綴拼進來(一般用不到)。

  然后就是,在Model模型類中,先取緩存,取不到則讀數(shù)據(jù)庫,讀到后不要忘了寫入緩存,設(shè)置好過期時間等細(xì)節(jié),就這么一個流程。

  當(dāng)然你還可以做得更加細(xì)致,比如讀取到緩存數(shù)據(jù)后,再檢測下它的過期時間,發(fā)現(xiàn)還有5秒就要過期了,于是我們重新給它設(shè)置為3000秒,這樣下次訪問時又能取到了,不至于下次又讀庫,頻繁地連接數(shù)據(jù)庫是很耗時的一件事。

  不過我還是覺得Redis好用,Redis中的Hash表最好的啦>-_-

  唔......不早了,洗洗睡~=_=

?

最佳 Windows 性能的頂級免費優(yōu)化軟件
最佳 Windows 性能的頂級免費優(yōu)化軟件

每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進程會占用資源并降低性能。幸運的是,許多工具可以讓 Windows 保持平穩(wěn)運行。

下載
相關(guān)標(biāo)簽:
來源:php中文網(wǎng)
本文內(nèi)容由網(wǎng)友自發(fā)貢獻,版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請聯(lián)系admin@php.cn
最新問題
開源免費商場系統(tǒng)廣告
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板
關(guān)于我們 免責(zé)申明 意見反饋 講師合作 廣告合作 最新更新
php中文網(wǎng):公益在線php培訓(xùn),幫助PHP學(xué)習(xí)者快速成長!
關(guān)注服務(wù)號 技術(shù)交流群
PHP中文網(wǎng)訂閱號
每天精選資源文章推送
PHP中文網(wǎng)APP
隨時隨地碎片化學(xué)習(xí)
PHP中文網(wǎng)抖音號
發(fā)現(xiàn)有趣的

Copyright 2014-2025 http://www.miracleart.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號