Yii2 framework backup
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

26 KiB

データキャッシュ

データキャッシュは PHP の変数をキャッシュに格納し、あとでキャッシュからそれらを読み込みます。 これは、クエリキャッシュページキャッシュ などの、より高度なキャッシュ機能の基礎でもあります。

以下のコードが、データキャッシュの典型的な利用パターンです。ここで、$cacheキャッシュコンポーネント を指しています。

// キャッシュから $data を取得しようと試みる
$data = $cache->get($key);

if ($data === false) {

    // キャッシュの中に $data が見つからない場合は一から作る
    $data = $this->calculateSomething();

    // $data をキャッシュに格納して、次回はそれを取得できるようにする
    $cache->set($key, $data);
}

// この時点で $data は利用可能になっている

バージョン 2.0.11 以降は、キャッシュコンポーネント が提供する yii\caching\Cache::getOrSet() メソッドを使って、 データを取得、計算、保存するためのコードを単純化することが出来ます。 次に示すコードは、上述の例と全く同じことをするものです。

$data = $cache->getOrSet($key, function () {
    return $this->calculateSomething();
});

キャッシュが $key と関連づけられたデータを保持している場合は、キャッシュされている値が返されます。 そうでない場合は、渡された無名関数が実行されて値が計算され、その値がキャッシュされるとともに返されます。

無名関数が外部のスコープの何らかのデータを必要とする場合は、それを use 文を使って渡すことが出来ます。 例えば、

$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
    return $this->calculateSomething($user_id);
});

Note: yii\caching\Cache::getOrSet() メソッドは、有効期限と依存もサポートしています。 詳しくは キャッシュの有効期限キャッシュの依存 を参照してください。

キャッシュコンポーネント

データキャッシュはメモリ、ファイル、データベースなどさまざまなキャッシュストレージを表す、いわゆる キャッシュコンポーネント に依存しています。

キャッシュコンポーネントは通常グローバルに設定しアクセスできるように アプリケーションコンポーネント として登録されます。 以下のコードは、二台のキャッシュサーバを用いる Memcached を使うように cache アプリケーションコンポーネントを構成する方法を示すものです。

'components' => [
    'cache' => [
        'class' => 'yii\caching\MemCache',
        'servers' => [
            [
                'host' => 'server1',
                'port' => 11211,
                'weight' => 100,
            ],
            [
                'host' => 'server2',
                'port' => 11211,
                'weight' => 50,
            ],
        ],
    ],
],

こうすると、上記のキャッシュコンポーネントに Yii::$app->cache という式でアクセスできるようになります。

すべてのキャッシュコンポーネントは同じ API をサポートしているので、アプリケーションの構成情報で設定しなおせば、キャッシュを使っているコードに変更を加えることなく、異なるキャッシュコンポーネントに入れ替えることができます。 例えば上記の構成を yii\caching\ApcCache を使うように変更する場合は以下のようにします:

'components' => [
    'cache' => [
        'class' => 'yii\caching\ApcCache',
    ],
],

Tip: キャッシュコンポーネントは複数登録することができます。cache という名前のコンポーネントが、キャッシュに依存する多数のクラスによってデフォルトで使用されます (例えば yii\web\UrlManager など) 。

サポートされているキャッシュストレージ

Yii はさまざまなキャッシュストレージをサポートしています。以下は概要です:

  • yii\caching\ApcCache: PHP の APC 拡張モジュールを使用します。 集中型の分厚いアプリケーションのキャッシュを扱うときには最速の一つとして考えることができます (例えば、サーバが一台で、専用のロードバランサを持っていない、などの場合)。
  • yii\caching\DbCache: キャッシュされたデータを格納するためにデータベースのテーブルを使用します。このキャッシュを使用するには yii\caching\DbCache::cacheTable で指定したテーブルを作成する必要があります。
  • yii\caching\DummyCache: 実際にはキャッシュを行わない、キャッシュのプレースホルダとして働きます。 このコンポーネントの目的は、キャッシュが利用できることをチェックするためのコードを簡略化することです。 たとえば、開発中やサーバに実際のキャッシュサポートがない場合に、このキャッシュを使用するようにキャッシュコンポーネントを構成することができます。 そして、実際のキャッシュサポートが有効になったときに、対応するキャッシュコンポーネントに切替えて使用します。 どちらの場合も、Yii::$app->cachenull かも知れないと心配せずに、データを取得するために同じコード Yii::$app->cache->get($key) を使用できます。
  • yii\caching\FileCache: キャッシュされたデータを保存するために通常のファイルを使用します。これはページコンテントなど大きなかたまりのデータに特に適しています。
  • yii\caching\MemCache: PHP の MemcacheMemcached 拡張モジュールを使用します。 分散型のアプリケーションでキャッシュを扱うときには最速の一つとして考えることができます (例えば、複数台のサーバで、ロードバランサがある、などの場合) 。
  • yii\redis\Cache: Redis の key-value ストアに基づいてキャッシュコンポーネントを実装しています。(Redis の バージョン 2.6.12 以降が必要です) 。
  • yii\caching\WinCache: PHP の WinCache (関連リンク) 拡張モジュールを使用します。
  • yii\caching\XCache (deprecated): PHP の XCache 拡張モジュールを使用します。
  • yii\caching\ZendDataCache (deprecated): キャッシュメディアして Zend Data Cache を使用します。

Tip: 同じアプリケーション内で異なるキャッシュを使用することもできます。一般的なやり方として、小さくとも常に使用されるデータ (例えば、統計データ) を格納する場合はメモリベースのキャッシュストレージを使用し、大きくて使用頻度の低いデータ (例えば、ページコンテント) を格納する場合はファイルベース、またはデータベースのキャッシュストレージを使用します 。

キャッシュ API

すべてのキャッシュコンポーネントが同じ基底クラス yii\caching\Cache を持っているので、以下の API をサポートしています。

  • yii\caching\Cache::get(): 指定されたキーを用いてキャッシュからデータを取得します。データが見つからないか、もしくは有効期限が切れたり無効になったりしている場合は false を返します。
  • yii\caching\Cache::set(): キーによって識別されるデータをキャッシュに格納します。
  • yii\caching\Cache::add(): キーがキャッシュ内で見つからない場合に、キーによって識別されるデータをキャッシュに格納します。
  • yii\caching\Cache::getOrSet(): 指定されたキーを用いてキャッシュからデータを取得します。 取得できなかった場合は、渡されたコールバック関数を実行し、関数の返り値をそのキーでキャッシュに保存し、そしてその値を返します。
  • yii\caching\Cache::multiGet(): 指定されたキーを用いてキャッシュから複数のデータを取得します。
  • yii\caching\Cache::multiSet(): キャッシュに複数のデータを格納します。各データはキーによって識別されます。
  • yii\caching\Cache::multiAdd(): キャッシュに複数のデータを格納します。各データはキーによって識別されます。もしキャッシュ内にキーがすでに存在する場合はスキップされます。
  • yii\caching\Cache::exists(): 指定されたキーがキャッシュ内で見つかったかどうかを示す値を返します。
  • yii\caching\Cache::delete(): キャッシュからキーによって識別されるデータを削除します。
  • yii\caching\Cache::flush(): キャッシュからすべてのデータを削除します。

Note: yii\caching\Cache::get() メソッドは、データがキャッシュ内に見つからないことを示すために戻り値として false を使用しているので、直接 boolean 型の false をキャッシュしないでください。 代りに配列内に false を置いてキャッシュすることによって、この問題を回避できます。

キャッシュされたデータを取得する際に発生するオーバーヘッドを減らすために、MemCache, APC などのいくつかのキャッシュストレージは、バッチモードで複数のキャッシュされた値を取得することをサポートしています。 yii\caching\Cache::multiGet()yii\caching\Cache::multiAdd() などの API はこの機能を十分に引き出すために提供されています。 基礎となるキャッシュストレージがこの機能をサポートしていない場合には、シミュレートされます。

yii\caching\CacheArrayAccess インターフェイスを継承しているので、キャッシュコンポーネントは配列のように扱うことができます。以下はいくつかの例です:

$cache['var1'] = $value1;  // $cache->set('var1', $value1); と同等
$value2 = $cache['var2'];  // $value2 = $cache->get('var2'); と同等

キャッシュのキー

キャッシュに格納される各データは、一意のキーによって識別されます。 キャッシュ内にデータを格納するときはキーを指定する必要があります。 また、あとでキャッシュからデータを取得するときは、それに対応するキーを提供しなければなりません。

キャッシュのキーとしては、文字列または任意の値を使用することができます。キーが文字列でない場合は、自動的に文字列にシリアライズされます。

キャッシュのキーを定義する一般的なやり方として、全ての決定要素を配列の形で含めるという方方があります。 例えば yii\db\Schema はデータベーステーブルのスキーマ情報を以下のキーを使用してキャッシュしています。

[
    __CLASS__,              // スキーマクラス名
    $this->db->dsn,         // データベース接続のデータソース名
    $this->db->username,    // データベース接続のログインユーザ
    $name,                  // テーブル名
];

見ての通り、キーは一意にデータベースのテーブルを指定するために必要なすべての情報を含んでいます。

Note: yii\caching\Cache::multiSet() または yii\caching\Cache::multiAdd() によってキャッシュに保存される値が持つことが出来るのは、 文字列または整数のキーだけです。それらより複雑なキーを設定する必要がある場合は、 yii\caching\Cache::set() または yii\caching\Cache::add() によって、値を個別に保存してください。

同じキャッシュストレージが異なるアプリケーションによって使用されているときは、キャッシュのキーの競合を避けるために、各アプリケーションではユニークなキーの接頭辞を指定する必要があります。これは yii\caching\Cache::keyPrefix プロパティを設定することでできます。例えば、アプリケーションのコンフィギュレーションで以下のように書くことができます:

'components' => [
    'cache' => [
        'class' => 'yii\caching\ApcCache',
        'keyPrefix' => 'myapp',       // ユニークなキャッシュのキーの接頭辞
    ],
],

相互運用性を確保するために、英数字のみを使用する必要があります。

キャッシュの有効期限

キャッシュに格納されたデータは、何らかのキャッシュポリシー (例えば、キャッシュスペースがいっぱいになったときは最も古いデータが削除される、など) の実施で除去されない限り、永遠に残り続けます。 この動作を変えるために yii\caching\Cache::set() を呼んでデータアイテムを保存するときに、有効期限パラメータを指定することができます。 このパラメータは、データアイテムが何秒間有効なものとしてキャッシュ内に残ることが出来るかを示します。 yii\caching\Cache::get() でデータアイテムを取得する際に有効期限が切れていた場合は、キャッシュ内にデータが見つからなかったことを示す false が返されます。例えば、

// 最大で 45 秒間キャッシュ内にデータを保持する
$cache->set($key, $data, 45);

sleep(50);

$data = $cache->get($key);
if ($data === false) {
    // $data は有効期限が切れているか、またはキャッシュ内に見つからない
}

バージョン 2.0.11 以降は、デフォルトの無限の有効期限に替えて特定の有効期限を指定したい場合には、キャッシュコンポーネントの構成で yii\caching\Cache::$defaultDuration の値を指定することが出来ます。 これによって、特定の duration パラメータを毎回 yii\caching\Cache::set() に渡さなくてもよくなります。

キャッシュの依存

有効期限の設定に加えて、キャッシュされたデータは、いわゆる キャッシュの依存 (キャッシュが依存している事物) の変化によって無効にすることもできます。 例えば yii\caching\FileDependency は、キャッシュがファイルの更新時刻に依存していることを表しています。 この依存が変化したときは、対応するファイルが更新されたことを意味します。 その結果、キャッシュ内で見つかった古いファイルのコンテントは、無効とされるべきであり yii\caching\Cache::get() は false を返さなければなりません。

キャッシュの依存は yii\caching\Dependency 子孫クラスのオブジェクトとして表現されます。 yii\caching\Cache::set() でキャッシュにデータアイテムを格納する際に、関連するキャッシュの依存のオブジェクトを一緒に渡すことができます。例えば、

// example.txt ファイルの更新時刻への依存を作成します。
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);

// データは 30 秒で期限切れになります。
// さらに、example.txt が変更された場合、有効期限内でも無効になります。
$cache->set($key, $data, 30, $dependency);

// キャッシュはデータの有効期限が切れているかをチェックします。
// 同時に、関連付けられた依存が変更されているかもチェックします。
// これらの条件のいずれかが満たされている場合は false を返します。
$data = $cache->get($key);

以下は利用可能なキャッシュの依存の概要です:

  • yii\caching\ChainedDependency: チェーン上のいずれかの依存が変更された場合に、依存が変更されます。
  • yii\caching\DbDependency: 指定された SQL 文のクエリ結果が変更された場合、依存が変更されます。
  • yii\caching\ExpressionDependency: 指定された PHP の式の結果が変更された場合、依存が変更されます。
  • yii\caching\FileDependency: ファイルの最終更新時刻が変更された場合、依存が変更されます。
  • yii\caching\TagDependency: キャッシュされるデータアイテムに一つまたは複数のタグを関連付けます。 yii\caching\TagDependency::invalidate() を呼び出すことによって、指定されたタグ (複数可) を持つキャッシュされたデータアイテムを無効にすることができます。

Note: 依存を有するキャッシュについて yii\caching\Cache::exists() メソッドを使用することは避けてください。 このメソッドは、キャッシュされたデータに関連づけられた依存がある場合でも、依存が変化したかどうかをチェックしません。 つまり、yii\caching\Cache::exists()true を返しているのに、 yii\caching\Cache::get()false を返すという場合があり得ます。

クエリキャッシュ

クエリキャッシュは、データキャッシュ上に構築された特別なキャッシュ機能で、データベースのクエリ結果をキャッシュするために提供されています。

クエリキャッシュは yii\db\Connection と有効な cache アプリケーションコンポーネント を必要とします。 $dbyii\db\Connection のインスタンスと仮定した場合、クエリキャッシュの基本的な使い方は以下のようになります:

$result = $db->cache(function ($db) {

    // クエリキャッシュが有効で、かつクエリ結果がキャッシュ内にある場合、
    // SQL クエリ結果がキャッシュから提供されます
    return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();

});

クエリキャッシュは DAO だけではなく アクティブレコード でも使用することができます。

$result = Customer::getDb()->cache(function ($db) {
    return Customer::find()->where(['id' => 1])->one();
});

Info: いくつかの DBMS (例えば MySQL) でもデータベースのサーバサイドのクエリキャッシュをサポートしています。 どちらのクエリキャッシュメカニズムも選べますが、前述した Yii のクエリキャッシュにはキャッシュの依存を柔軟に指定できるという利点があり、潜在的にはより効率的でしょう。

2.0.14 以降は、下記のショートカットを使用することが出来ます。

(new Query())->cache(7200)->all();
// および
User::find()->cache(7200)->all();

構成

クエリキャッシュには yii\db\Connection を通して設定可能な三つのグローバルなオプションがあります:

  • yii\db\Connection::enableQueryCache: クエリキャッシュを可能にするかどうか。デフォルトは true です。 実効的にクエリキャッシュをオンにするには yii\db\Connection::queryCache によって指定される有効なキャッシュを持っている必要があることに注意してください。
  • yii\db\Connection::queryCacheDuration: これはクエリ結果がキャッシュ内に有効な状態として持続できる秒数を表します。 クエリキャッシュを永遠にキャッシュに残したい場合は 0 を指定することができます。 このプロパティは yii\db\Connection::cache() が持続時間を指定せず呼び出されたときに使用されるデフォルト値です。
  • yii\db\Connection::queryCache: これはキャッシュアプリケーションコンポーネントの ID を表します。 デフォルトは 'cache' です。有効なキャッシュコンポーネントが存在する場合にのみ、クエリキャッシュが使用可能になります。

使い方

クエリキャッシュを使用する必要がある複数の SQL クエリを持っている場合は yii\db\Connection::cache() を使用することができます。使い方としては以下のように、

$duration = 60;     // クエリ結果を 60 秒間 キャッシュ
$dependency = ...;  // 依存のオプション

$result = $db->cache(function ($db) {

    // ... ここで SQL クエリを実行します ...

    return $result;

}, $duration, $dependency);

無名関数内の任意の SQL クエリは、指定した依存とともに指定された期間キャッシュされます。 もしキャッシュ内に有効なクエリ結果が見つかった場合は、クエリはスキップされ、代りに結果がキャッシュから提供されます。 $duration の指定がない場合 yii\db\Connection::queryCacheDuration で指定されている値が代りに使用されます。

また、cache() 内でいくつかの特定のクエリに対してクエリキャッシュを無効にすることもできます。この場合 yii\db\Connection::noCache() を使用します。

$result = $db->cache(function ($db) {

    // クエリキャッシュを使用する SQL クエリ

    $db->noCache(function ($db) {

        // クエリキャッシュを使用しない SQL クエリ

    });

    // ...

    return $result;
});

単一のクエリのためにクエリキャッシュを使用する場合は、コマンドを構築するときに yii\db\Command::cache() を呼び出すことができます。例えば、

// クエリキャッシュを使い、期間を 60 秒にセットする
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();

また、一つのコマンドに対してクエリキャッシュを無効にするために yii\db\Command::noCache() を使用することもできます。例えば、

$result = $db->cache(function ($db) {

    // クエリキャッシュを使用する SQL クエリ

    // このコマンドはクエリキャッシュを使用しない
    $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne();

    // ...

    return $result;
});

制約

リソースハンドラを返すようなクエリにはクエリキャッシュは働きません。 例えば、いくつかの DBMS において BLOB 型のカラムを用いる場合、クエリ結果はカラムデータに対するリソースハンドラを返します。

いくつかのキャッシュストレージはサイズに制約があります。例えば Memcache では、各エントリのサイズは 1MB が上限値です。そのためクエリ結果のサイズがこの制約を越える場合、キャッシュは失敗します。

キャッシュのフラッシュ

保存されている全てのキャッシュデータを無効化する必要がある場合は、yii\caching\Cache::flush() を呼ぶことが出来ます。

コンソールから yii cache/flush を呼ぶことによっても、キャッシュをフラッシュすることが出来ます。

  • yii cache: アプリケーションで利用可能なキャッシュのリストを表示します。
  • yii cache/flush cache1 cache2: キャッシュコンポーネント cache1cache2 をフラッシュします (複数のコンポーネント名をスペースで区切って渡すことが出来ます)
  • yii cache/flush-all: アプリケーションの全てのキャッシュコンポーネントをフラッシュします。

Info: デフォルトでは、コンソールアプリケーションは独立した構成情報ファイルを使用します。 正しい結果を得るためには、ウェブとコンソールのアプリケーション構成で同じキャッシュコンポーネントを使用していることを確認してください。