php 版本——未經(jīng)測試,僅做參考
-
使用時,繼承此類并實現(xiàn)對應(yīng)方法
<?php /** * * 適用于redis + db 的存儲形式,存儲數(shù)據(jù)為按一定規(guī)則排序的id列表,適用于: * 緩存中的key使用sorted set, 且設(shè)置過期時間而非持久化存儲 * 分頁獲取數(shù)據(jù)時按排序的值, 即cursor->score來獲取:獲取比cursor->score小【或大】的length條數(shù)據(jù) * * 使用場景如: * 文章按發(fā)布時間排序,按評論數(shù)排序,按點贊數(shù)排序 * * User: xjyin * Date: 15/11/5 * Time: 下午7:45 */ class Cursor { private $member; private $score; } abstract class CursorTimelineGetter { private $cursor; private $length; function _construct($cursor, $length) { $this->cursor = $cursor; $this->length = $length; } // 返回數(shù)據(jù)為cursor的array, 長度可能會小于$length abstract protected function getFromCache($cursor, $length); // 返回數(shù)據(jù)為cursor的array, 長度可能會小于$length abstract protected function getFromDB($cursor, $length); // 將從數(shù)據(jù)庫中獲取到的數(shù)據(jù)放到緩存, dbResults 為cursor 的array abstract protected function saveToCache($dbResults); // 將不夠的數(shù)據(jù)補到緩存中,否則將會造成數(shù)據(jù)丟失 // 在實現(xiàn)此方法時用zAdd(key, map)的方式,避免循環(huán)調(diào)用單個member 的zAdd abstract protected function patchToCache($cursor); public function exec() { $cacheResults = $this->getFromCache($this->cursor, $this->length); if(!$cacheResults) { $cacheResults = array(); } // 若緩存中已經(jīng)獲取到所有分頁數(shù)據(jù),則直接返回 if(count($cacheResults) >= $this->length) { return $cacheResults; } // 緩存中數(shù)據(jù)不全時,從數(shù)據(jù)庫中獲取不夠的 $lengthFromDB = $this->length - count($cacheResults); $cursorFromDb = null; // 從緩存中獲取到的數(shù)據(jù)為空時,需要將cursor之前的數(shù)據(jù)從db拉到cache中,否則會丟數(shù)據(jù) // 只要從緩存中獲取的數(shù)據(jù)非空,則不存在此情況,不需要調(diào)用patchToCache if (count($cacheResults) <= 0) { $this->patchToCache($this->cursor); $cursorFromDb = $this->cursor; } else { $cursorFromDb = $cacheResults[count($cacheResults) - 1]; } $dbResults = $this->getFromDB($cursorFromDb, $lengthFromDB); if(!$dbResults or count($dbResults) == 0) { return $cacheResults; } $this->saveToCache($dbResults); return array_merge($cacheResults, $dbResults); } }