1. 程式人生 > >TP模型增刪改後cache查詢快取無法更新問題的解決辦法

TP模型增刪改後cache查詢快取無法更新問題的解決辦法

TP模型連貫操作cache方法用於select、find和getField方法,以及其衍生方法,使用cache方法後,在快取有效期之內不會再次進行資料庫查詢操作,而是直接獲取快取中的資料。
第一次查詢結果會被快取,第二次查詢相同的資料的時候就會直接返回快取中的內容,而不需要再次進行資料庫查詢操作。

預設情況下, 快取有效期和快取型別是由DATA_CACHE_TIME和DATA_CACHE_TYPE配置引數決定的,但cache方法可以單獨指定。

例如:
$Model->where('id=5')->cache(true)->find(); // 自動命名快取ID,使用系統預設DATA_CACHE_TIME(0=永久有效)

$Model->cache('key',60)->find(); // 自定義快取ID,60秒後失效

問題:
快取有效期當然是越久越好,所以預設DATA_CACHE_TIME=0,也就是永久有效。那麼問題來了,資料表增刪改操作後,如何使查詢快取的資料更新呢?
用S('key',null),那不行,因為查詢中用了cache(true),你根本不知道key的具體值,而且如果查詢中包含了動態的where查詢,那可能會產生多個快取。

如果設定了快取有效期cache(true,5),也就是5秒後沒有命中該查詢快取的話,快取會自動失效。這是比較簡單的兩頭兼顧的方法,但是也有問題,在高併發情況下,快取持續被命中,則快取持續生效,就沒有機會重新從資料表獲取增刪改後的新資料。對增刪改後要求資料查詢也立即生效的情景中,快取重新整理成了一個大問題。


綜上所述,需改造一下Model類,在select(),find(),getField()方法中,有啟用快取的情況下,增加一個快取記錄邏輯。在add(), save(), delete(), setField()方法中,在有啟用快取的情況下,增加一個清理快取的邏輯。

==================方法如下:(可作為公開方法放在Model類中,也可以作為函式放在公共函式庫function.php中)===================

/**
* 清理資料表查詢快取

* 用於解決資料表增刪改操作無法重新整理查詢快取(特別是cache(true)自動命名的快取)的問題
* 只需在增刪改操作成功時,呼叫clear_table_caching($table);

* 即可使對應此表的所有查詢快取失效.

* 預設在模型的add,save,delete,setField等操作中會自動呼叫

* @param string $table 資料表名稱
* @since 1.0 <2015-4-30> SoChishun Added;
*/
function clear_table_caching($table = '') {
$table_caching_keys = F('table_caching_keys');
if (!$table_caching_keys) {
return;
}
// 清理指定表的快取
if ($table) {
if (isset($table_caching_keys[$table])) {
$values = $table_caching_keys[$table];
foreach ($values as $id) {
S($id, null);
}
unset($table_caching_keys[$table]);
F('table_caching_keys', $table_caching_keys);
}
return;
}
// 清理所有表的快取
foreach ($table_caching_keys as $values) {
foreach ($values as $id) {
S($id, null);
}
}
F('table_caching_keys', null);
}

/**
* 新增快取鍵名到資料表查詢集合中

* 用於提供clear_table_caching()方法的資料呼叫

* 預設在getField,select,find等方法中自動呼叫

* @param string $table 資料表名稱
* @param string $id 快取鍵名
* @since 1.0 <2015-4-30> SoChishun Added.
*/
function log_table_cacheing($table, $id) {
$table_caching_keys = F('table_caching_keys');
if ($table_caching_keys && isset($table_caching_keys[$table]) && in_array($id, $table_caching_keys[$table])) {
return; // 如果已經存在則退出
}
$table_caching_keys[$table][] = $id;
F('table_caching_keys', $table_caching_keys);
}
============
使用方法(Model類中):
$this->log_table_cacheing($options['table'], $key); // 記錄資料表的快取鍵
$this->clear_table_caching($options['table']); // 清除資料表的所有查詢快取
============

希望官方考慮到此問題,釋出官方解決方案:)