标签归档:cache

Zend Framework 2.x 之 Zend\Cache

Zend\Cache

Zend\Cache\Storage\Adapter

Overview

*Storage adapters are wrappers for real storage resources such as memory and the filesystem, using the well known adapter pattern.

*They come with tons of methods to read, write and modify stored items and to get information about stored items and the storage.

*All adapters implement the interface Zend\Cache\Storage\StorageInterface and most extend Zend\Cache\Storage\Adapter\AbstractAdapter, which comes with basic logic.

*Configuration is handled by either Zend\Cache\Storage\Adapter\AdapterOptions, or an adapter-specific options class if it exists. You may pass the options instance to the class at instantiation or via the setOptions() method, or alternately pass an associative array of options in either place (internally, these are then passed to an options class instance). Alternately, you can pass either the options instance or associative array to the Zend\Cache\StorageFactory::factory method.

Note
Many methods throw exceptions

Because many caching operations throw an exception on error, you need to catch them manually or you can use the plug-in Zend\Cache\Storage\Plugin\ExceptionHandler with throw_exceptions set to false to automatically catch them. You can also define an exception_callback to log exceptions.

Quick Start

*Caching adapters can either be created from the provided Zend\Cache\StorageFactory factory, or by simply instantiating one of the Zend\Cache\Storage\Adapter\* classes. 可通过工厂,或直接创建

*To make life easier, the Zend\Cache\StorageFactory comes with a factory method to create an adapter and create/add all requested plugins at once.

use Zend\Cache\StorageFactory;

// Via factory:
$cache = StorageFactory::factory(array(
    'adapter' => array(
        'name'    => 'apc',
        'options' => array('ttl' => 3600),
    ),
    'plugins' => array(
        'exception_handler' => array('throw_exceptions' => false),
    ),
));

// Alternately:
$cache  = StorageFactory::adapterFactory('apc', array('ttl' => 3600));
$plugin = StorageFactory::pluginFactory('exception_handler', array(
    'throw_exceptions' => false,
));
$cache->addPlugin($plugin);

// Or manually:
$cache  = new Zend\Cache\Storage\Adapter\Apc();
$cache->getOptions()->setTtl(3600);

$plugin = new Zend\Cache\Storage\Plugin\ExceptionHandler();
$plugin->getOptions()->setThrowExceptions(false);
$cache->addPlugin($plugin);

Basic Configuration Options

*Basic configuration is handled by either Zend\Cache\Storage\Adapter\AdapterOptions, or an adapter-specific options class if it exists. You may pass the options instance to the class at instantiation or via the setOptions() method, or alternately pass an associative array of options in either place (internally, these are then passed to an options class instance). Alternately, you can pass either the options instance or associative array to the Zend\Cache\StorageFactory::factory method.

*The following configuration options are defined by Zend\Cache\Storage\Adapter\AdapterOptions and are available for every supported adapter. Adapter-specific configuration options are described on adapter level below.

Option Data Type Default Value Description
ttl integer 0 Time to live
namespace string “zfcache” The “namespace” in which cache items will live
key_pattern null``|``string null Pattern against which to validate cache keys
readable boolean true Enable/Disable reading data from cache
writable boolean true Enable/Disable writing data to cache

实际,真要使用,就上面的简单代码。有大量的适配器,基本上,每个适配器都对应一个Option对象。可用的选项是不一样的,而公共的就是上面给出的这些。

….

PHP框架Phalcon 之 在ORM中缓存

Caching in the ORM 在ORM中缓存
Every application is different, we could have models whose data change frequently and others that rarely change. Accessing database systems is often one of the most common bottlenecks in terms of performance. This is due to the complex connection/communication processes that PHP must do in each request to obtain data from the database. Therefore, if we want to achieve good performance we need to add some layers of caching where the application requires it.
不经常改变的数据要缓存起来…

This chapter explains the possible points where it is possible to implement caching to improve performance. The framework gives you the tools to implement the cache where you demand of it according to the architecture of your application.
说它提供了缓存。

Caching Resultsets 缓存结果集
A well established technique to avoid the continuous access to the database is to cache resultsets that don’t change frequently using a system with faster access (usually memory).
把不经常改变的结果集缓存起来。

When Phalcon\Mvc\Model requires a service to cache resultsets, it will request it to the Dependency Injector Container with the convention name “modelsCache”.
当Phalcon\Mvc\Model要去缓存结果集,它会通过DI容器获取“modelsCache”(这个是缓存对象,复杂读取写入缓存)。

As Phalcon provides a component to cache any kind of data, we’ll explain how to integrate整合 it with Models. First, you must register it as a service in the services container:
首先要在容器中注册:

<?php

//Set the models cache service
$di->set('modelsCache', function() {

    //Cache data for one day by default
    $frontCache = new \Phalcon\Cache\Frontend\Data(array(
        "lifetime" => 86400
    ));

    //Memcached connection settings
    $cache = new \Phalcon\Cache\Backend\Memcache($frontCache, array(
        "host" => "localhost",
        "port" => "11211"
    ));

    return $cache;
});

You have complete control in creating and customizing the cache before being used by registering the service as an anonymous function. Once the cache setup is properly defined you could cache resultsets as follows:
可以通过匿名函数完全控制缓存对象的创建和定制。如下缓存结果集:

<?php

// Get products without caching
$products = Products::find();

// Just cache the resultset. The cache will expire in 1 hour (3600 seconds)
$products = Products::find(array(
    "cache" => array("key" => "my-cache")
));

// Cache the resultset for only for 5 minutes
$products = Products::find(array(
    "cache" => array("key" => "my-cache", "lifetime" => 300)
));

// Using a custom cache(取回缓存的方法)
$products = Products::find(array("cache" => $myCache));

Caching could be also applied to resultsets generated using relationships:
缓存也可以应用到由关系产生的结果集

<?php

// Query some post
$post = Post::findFirst();

// Get comments related to a post, also cache it
$comments = $post->getComments(array(
    "cache" => array("key" => "my-key")
));

// Get comments related to a post, setting lifetime
$comments = $post->getComments(array(
    "cache" => array("key" => "my-key", "lifetime" => 3600)
));

When a cached resultset needs to be invalidated, you can simply delete it from the cache using the previously specified key.
缓存无效,可以通过指定的key删除。

Note that not all resultsets must be cached. Results that change very frequently should not be cached since they are invalidated very quickly and caching in that case impacts performance. Additionally, large datasets that do not change frequently could be cached, but that is a decision that the developer has to make based on the available caching mechanism and whether the performance impact to simply retrieve that data in the first place is acceptable.(一段废话)

Overriding find/findFirst 重写find/findFirst
As seen above, these methods are available in models that inherit Phalcon\Mvc\Model:

<?php

class Robots extends Phalcon\Mvc\Model
{

    public static function find($parameters=null)
    {
        return parent::find($parameters);
    }

    public static function findFirst($parameters=null)
    {
        return parent::findFirst($parameters);
    }

}

By doing this, you’re intercepting all the calls to these methods, this way, you can add a cache layer or run the query if there is no cache. For example, a very basic cache implementation, uses a static property to avoid that a record would be queried several times in a same request:
重写这两个方法,添加缓存层:

<?php

class Robots extends Phalcon\Mvc\Model
{

    protected static $_cache = array();

    /**
     * Implement a method that returns a string key based
     * on the query parameters
     */
    protected static function _createKey($parameters)
    {
        $uniqueKey = array();
        foreach ($parameters as $key => $value) {
            if (is_scalar($value)) {
                $uniqueKey[] = $key . ':' . $value;
            } else {
                if (is_array($value)) {
                    $uniqueKey[] = $key . ':[' . self::_createKey($value) .']';
                }
            }
        }
        return join(',', $uniqueKey);
    }

    public static function find($parameters=null)
    {

        //Create an unique key based on the parameters
        $key = self::_createKey($parameters);

        if (!isset(self::$_cache[$key])) {
            //Store the result in the memory cache
            self::$_cache[$key] = parent::find($parameters);
        }

        //Return the result in the cache
        return self::$_cache[$key];
    }

    public static function findFirst($parameters=null)
    {
        // ...
    }

}

Access the database is several times slower than calculate a cache key, you’re free in implement the key generation strategy you find better for your needs. Note that a good key avoids collisions as much as possible, this means that different keys returns unrelated records to the find parameters.

In the above example, we used a cache in memory, it is useful as a first level cache. Once we have the memory cache, we can implement a second level cache layer like APC/XCache or a NoSQL database:
实现第二层次缓存:

<?php

public static function find($parameters=null)
{

    //Create an unique key based on the parameters
    $key = self::_createKey($parameters);

    if (!isset(self::$_cache[$key])) {

        //We're using APC as second cache
        if (apc_exists($key)) {

            $data = apc_fetch($key);

            //Store the result in the memory cache
            self::$_cache[$key] = $data;

            return $data;
        }

        //There are no memory or apc cache
        $data = parent::find($parameters);

        //Store the result in the memory cache
        self::$_cache[$key] = $data;

        //Store the result in APC
        apc_store($key, $data);

        return $data;
    }

    //Return the result in the cache
    return self::$_cache[$key];
}

This gives you full control on how the the caches must be implemented for each model, if this strategy is common to several models you can create a base class for all of them:
建立一个公共模型,然后让其它模型继承它,那么就可以使用自定义的缓存策略。

<?php

class CacheableModel extends Phalcon\Mvc\Model
{

    protected static function _createKey($parameters)
    {
        // .. create a cache key based on the parameters
    }

    public static function find($parameters=null)
    {
        //.. custom caching strategy
    }

    public static function findFirst($parameters=null)
    {
        //.. custom caching strategy
    }
}

Then use this class as base class for each ‘Cacheable’ model:

<?php

class Robots extends CacheableModel
{

}

Forcing Cache
这个内容跟以上内容重复。

Caching PHQL Queries PHQL查询缓存
All queries in the ORM, no matter how high level syntax we used to create them are handled internally using PHQL. This language gives you much more freedom to create all kinds of queries. Of course these queries can be cached:
内部都使用PHQL,这种查询可以被缓存:(PHQL先装换成IR,这里就是缓存这个IR)

<?php

$phql = "SELECT * FROM Cars WHERE name = :name:";

$query = $this->modelsManager->createQuery($phql);

$query->cache(array(
    "key" => "cars-by-name",
    "lifetime" => 300
));

$cars = $query->execute(array(
    'name' => 'Audi'
));

(注意,缓存对象务必要在DI中先注册)

If you don’t want to use the implicit cache just save the resulset into your favorite cache backend:

<?php

$phql = "SELECT * FROM Cars WHERE name = :name:";

$cars = $this->modelsManager->executeQuery($phql, array(
    'name' => 'Audi'
));

apc_store('my-cars', $cars);

Reusable Related Records
Caching Related Records
Caching Related Records Recursively
Caching based on Conditions
Caching of PHQL planning