caching system


##Cache system

  • Configuration
    • Driver prerequisites
  • Use of cache
    • Get cache instance
    • Get data from cache
    • Store data in cache
    • Delete data in cache
    • Atomic lock
    • Cache auxiliary function
  • Cache tag
    • Write the marked cache data
    • Access marked cache data
    • Remove marked cache data
  • Add Custom cache driver
    • Write driver
    • Register driver
  • ## Event

Configuration

Laravel provides rich and unified caching for various backends API, its configuration information is located in the

config/cache.php

file. In this file you can specify which cache driver the application uses by default. Laravel supports currently popular backend caches, such as Memcached and Redis. The cache configuration file also contains various other options, which are documented in the file, so be sure to read these options. By default, Laravel is configured to use the

file

cache driver, which stores serialized cache objects in the file system. For larger applications, it is recommended that you use a more powerful driver such as Memcached or Redis. You can even configure multiple cache configurations for the same driver.

Driver prerequisites

Database

When using the database cache driver, you need to configure a table to store cache data. The following is an example of the Schema declaration to build the cache data table structure:

Schema::create('cache', function ($table) {
    $table->string('key')->unique();    
    $table->text('value');    
    $table->integer('expiration');
});

{tip} You can also use the Artisan command php artisan cache:table to generate it Suitable migration.

Memcached

Using the Memcached driver requires installing the Memcached PECL extension package. You can list all Memcached servers in the config/cache.php configuration file:

'memcached' => [ 
   [       
    'host' => '127.0.0.1',        
    'port' => 11211,        
    'weight' => 100    
   ],
 ],

You can set the host option to the UNIX socket path. If you configure it this way, the port option should be set to 0:

'memcached' => [ 
   [      
     'host' => '/var/run/memcached/memcached.sock',        
     'port' => 0,        
     'weight' => 100   
    ],
],

Redis

When using Laravel's Redis Before caching, you need to install the predis/predis extension package (~1.0) through Composer or use PECL to install the PhpRedis PHP extension.

To learn more about Redis configuration, please refer to the Laravel Redis documentation.

Use of cache

Get cache instance

Illuminate\Contracts\Cache\Factory and Illuminate\Contracts\Cache\Repository contracts provide the access mechanism for Laravel cache services. Factory The contract defines the mechanism for your application to access all cache drivers. Repository The contract is usually implemented by the default cache driver specified in your cache configuration file.

However, you can also use the Cache Facade, which we will introduce in subsequent documents. Cache Facade provides a convenient and concise method for the underlying implementation of Laravel cache contract:

<?php
    namespace App\Http\Controllers;
    use Illuminate\Support\Facades\Cache;
    class UserController extends Controller{   
     /**
     * 展示应用的所有用户列表。
     *
     * @return Response
     */ 
      public function index() 
         {     
            $value = Cache::get('key');    
                //  
          }
     }

Access multiple cache storage

UseCache Facade, you can access various cache stores through the store method. The key passed into the store method should correspond to one of the stores listed in the stores configuration array in the cache configuration information file:

$value = Cache::store('file')->get('foo');
Cache::store('redis')->put('bar', 'baz', 600); 
// 10 分钟

Get data from the cache

Cache The get method of Facade is the method used to get data from the cache. If the data does not exist in the cache, the method will return null. As you might imagine, you can also pass a second parameter to the get method to specify the default value you want returned if the data being looked up does not exist:

$value = Cache::get('key');
$value = Cache::get('key', 'default');

You can even Closure can be passed as the default value. If the specified data does not exist in the cache, the result of Closure will be returned. Methods passing a closure allow you to get the default value from a database or other external service:

$value = Cache::get('key', function () {
    return DB::table(...)->get();
 });

Check if the cache item exists

has method Can be used to determine whether cache items exist. If it is null or false, this method will return false:

if (Cache::has('key')) { 
   //
}

Incrementing and decrementing values## The

#increment and decrement methods can be used to adjust the value of an integer item in the cache. Both methods can pass in a second optional parameter, which is used to specify the amount to be incremented or decremented:

Cache::increment('key');
Cache::increment('key', $amount);
Cache::decrement('key');
Cache::decrement('key', $amount);

Getting and storing

Sometimes You may want to get a data from the cache, and when the requested cache item does not exist, the program can store a default value for you. For example, you may want to get all users from the cache. When these users do not exist in the cache, the program will fetch these users from the database and put them in the cache. You can use the

Cache::remember method to achieve this:

$value = Cache::remember('users', $seconds, function () {
    return DB::table('users')->get();
 });

If the data you want does not exist in the cache, pass it to the

remember method The closure will be executed and its result returned and placed in the cache.

You can get data from the cache or store it permanently using the

rememberForever method:

$value = Cache::rememberForever('users', function () {
    return DB::table('users')->get();
});

Get and delete

if You need to get the data from the cache before deleting it. You can use the

pull method. Like the get method, if the cache does not exist, null is returned:

$value = Cache::pull('key');

Storing data in the cache

You can use the

put method of the Cache Facade to store data in the cache:

Cache::put('key', 'value', $seconds);

If the cache expires If the time is not passed to the

put method, the cache will be valid forever:

Cache::put('key', 'value');

In addition to passing the expiration time in seconds as an integer, you can also pass a

DateTime instance To indicate the expiration time of the data:

Cache::put('key', 'value', now()->addMinutes(10));

Only store data that does not exist

add The method will only store data that does not exist in the cache. If the storage is successful, true will be returned, otherwise false will be returned:

Cache::add('key', 'value', $seconds);

Data Permanent Storage

forever method can be used to persistently store data into the cache. Because these data do not expire, they must be manually removed from the cache via the forget method:

Cache::forever('key', 'value');

{tip} If you use the Memcached driver, when the cached data reaches the storage For a limited time, data in "persistent storage" may be deleted.

Delete the data in the cache

You can use the forget method from Delete this data from the cache:

Cache::forget('key');

You can also delete this data by providing a zero or negative TTL value:

Cache::put('key', 'value', 0);
Cache::put('key', 'value', -5);

You can use the flush method to clear all caches :

Cache::flush();

{note} The method of clearing the cache does not consider the cache prefix and will delete all content in the cache. So please consider carefully when clearing cache shared with other applications.

Atomic Lock

{note} To use this feature, your application must Use the memcached, dynamodb or redis cache driver as the default cache driver for your application. Additionally, all servers must communicate with the same central cache server.

Atomic locks allow operations on distributed locks without worrying about race conditions. For example, Laravel Forge uses atomic locks to ensure that only one remote task is executed on a server at a time. You can create and manage locks using the Cache::lock method: The

use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
    //获取锁定10秒...    
    $lock->release();
}

get method can also receive a closure. After the closure is executed, Laravel will automatically release the lock:

Cache::lock('foo')->get(function () {
    // 获取无限期锁并自动释放...
});

If the lock is not available at the time of your request, you can control Laravel to wait for a specified number of seconds. If the lock cannot be acquired within the specified time limit, Illuminate\Contracts\Cache\LockTimeoutException will be thrown:

use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);try {
    $lock->block(5);    
    // 等待最多5秒后获取的锁...
   } catch (LockTimeoutException $e) {
       // 无法获取锁...
   } finally {
       optional($lock)->release();
   }
Cache::lock('foo', 10)->block(5, function () {
    // 等待最多5秒后获取的锁...
   });

Manage cross-process locks

Sometimes, you want to acquire a lock in one process and release it in another process. For example, you could acquire a lock during a web request and want to release the lock when the queue job triggered by that request ends. In this case, you should pass the lock's scope "owner token" to the queue job so that the job can re-instantiate the lock with the given token:

// 控制器里面...
$podcast = Podcast::find($id);
if ($lock = Cache::lock('foo', 120)->get()) {
    ProcessPodcast::dispatch($podcast, $lock->owner());
    }
// ProcessPodcast Job 里面...
Cache::restoreLock('foo', $this->owner)->release();

If you want to do this without respecting the current lock To release the lock without the owner, you can use the forceRelease method:

Cache::lock('foo')->forceRelease();

Cache auxiliary function

In addition to using the Cache Facade or Cache contract, you can also use the global auxiliary function cache to obtain and save cache data. When the cache function only receives a string parameter, it will return the value corresponding to the given key:

$value = cache('key');

If you provide the function with a set of key-value pairs and expiration time , it will cache the data for the specified time:

cache(['key' => 'value'], $seconds);
cache(['key' => 'value'], now()->addMinutes(10));

When the cache function is called without any parameters, it returns a Illuminate\Contracts\Cache\ An instance of the Factory implementation that allows you to call other cache methods:

cache()->remember('users', $seconds, function () {
    return DB::table('users')->get();
 });

{tip} If you use the global helper function cache in your tests, you can use The Cache::shouldReceive method is like testing the Facade.

Cache tag

{note} Cache tag is not supported using file and database cache drivers. In addition, a cache driver like memcached performs best when the cache using multiple cache tags is set to "persistent", which automatically clears old records.

Write tagged cache data

Cache tags allow you to tag cache related data. So that these cached values ​​can be cleared later. You can access the cache of tags by passing in an ordered array of tag names. For example, we can set the cache using the put method while using the tag.

Cache::tags(['people', 'artists'])->put('John', $john, $seconds);
Cache::tags(['people', 'authors'])->put('Anne', $anne, $seconds);

Access marked cache data

To obtain a marked cache data, please change the same Pass an ordered array of tags to the tags method, then call the get method to get the key you want to retrieve:

$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');

Remove marked cache data

You can clear all cached data with a single mark or a group of marks. For example, the following statement would be cached as people, authors, or both. Therefore, both Anne and John will be deleted from the cache:

Cache::tags(['people', 'authors'])->flush();

In contrast, the following statement will only delete the cache marked authors , so Anne will be deleted, but John will not:

Cache::tags('authors')->flush();

increase Custom cache driver

Writing Driver

To create a custom cache driver, you first need to implement the Illuminate\Contracts\Cache\Store contract. Therefore, MongoDB's cache implementation will look like this:

<?php
    namespace App\Extensions;
    use Illuminate\Contracts\Cache\Store;
    class MongoStore implements Store{ 
       public function get($key) {}    
       public function many(array $keys);    
       public function put($key, $value, $seconds) {}    
       public function putMany(array $values, $seconds);    
       public function increment($key, $value = 1) {}    
       public function decrement($key, $value = 1) {}    
       public function forever($key, $value) {}    
       public function forget($key) {}    
       public function flush() {}    
       public function getPrefix() {}
    }

We only need the MongoDB connection to implement these methods. For examples of how to implement these methods, see Illuminate\Cache\MemcachedStore in the framework source code. Once the contract is completed, you can complete the registration of the custom driver as follows.

Cache::extend('mongo', function ($app) {
    return Cache::repository(new MongoStore);
  });

{tip} If you don't know where to put the cache driver code, you can create an Extensions namespace in the app directory. However, Laravel does not dictate the structure of your application and you are free to organize your application however you like.

Register driver

To use Laravel to register a custom cache driver, you must Cache Use the extend method on the Facade. The call to Cache::extend can be done in the boot method of App\Providers\AppServiceProvider that comes with the new Laravel application, or you can also You can create your own service provider to store extensions, but don't forget to register the service provider in the provider array of config/app.php:

<?php
    namespace App\Providers;use App\Extensions\MongoStore;
    use Illuminate\Support\Facades\Cache;
    use Illuminate\Support\ServiceProvider;
    class CacheServiceProvider extends ServiceProvider{   
     /**
     * 执行服务的注册后引导。
     *
     * @return void
     */   
       public function boot()   
        {      
          Cache::extend('mongo', function ($app) {     
                 return Cache::repository(new MongoStore);        
             });   
          }   
     /**
     * 在容器中注册绑定。
     *
     * @return void
     */    
     public function register()   
      {      
        //   
       }
    }

is passed to extend The first parameter of the method is the name of the driver. This will correspond to the driver option of the config/cache.php configuration file. The second parameter is a closure that should return an instance of Illuminate\Cache\Repository. The closure will be passed an $app instance of the service container.

Once your extension is registered, you need to update the driver option in the config/cache.php configuration file to your extension name.

Events

To execute code on every cache operation, you can listen to events triggered by the cache. Typically, you should place these event listeners in EventServiceProvider:

/**
 * 应用的事件监听器映射
 *
 * @var array
 */
 protected $listen = [
     'Illuminate\Cache\Events\CacheHit' => [   
          'App\Listeners\LogCacheHit',   
         ],    
     'Illuminate\Cache\Events\CacheMissed' => [     
        'App\Listeners\LogCacheMissed',  
         ],    
     'Illuminate\Cache\Events\KeyForgotten' => [    
         'App\Listeners\LogKeyForgotten',  
          ],   
      'Illuminate\Cache\Events\KeyWritten' => [ 
          'App\Listeners\LogKeyWritten', 
           ],
        ];
This article first appeared on the LearnKu.com website.