CacheModelTrait.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. <?php
  2. /**
  3. * +----------------------------------------------------------------------
  4. * | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  5. * +----------------------------------------------------------------------
  6. * | Copyright (c) 2016~2022 https://www.crmeb.com All rights reserved.
  7. * +----------------------------------------------------------------------
  8. * | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  9. * +----------------------------------------------------------------------
  10. * | Author: CRMEB Team <admin@crmeb.com>
  11. * +----------------------------------------------------------------------
  12. */
  13. namespace qiniu\traits;
  14. use qiniu\services\CacheService;
  15. use qiniu\utils\Tag;
  16. use think\cache\TagSet;
  17. use think\Container;
  18. use think\facade\Cache;
  19. use think\facade\Log;
  20. use think\Model;
  21. /**
  22. * Trait CacheDaoTrait
  23. * @package crmeb\traits\dao
  24. * @method Model getModel()
  25. * @method Model getPk()
  26. */
  27. trait CacheModelTrait
  28. {
  29. /**
  30. * 获取redis
  31. * @return object|null
  32. * @author 等风来
  33. * @email 136327134@qq.com
  34. * @date 2022/10/29
  35. */
  36. private function getRedisConnect()
  37. {
  38. return CacheService::redisHandler()->handler();
  39. }
  40. /**
  41. * 获取缓存
  42. * @return TagSet|Cache
  43. * @author 等风来
  44. * @email 136327134@qq.com
  45. * @date 2022/11/10
  46. */
  47. private function getCacheHandler()
  48. {
  49. return CacheService::redisHandler();
  50. }
  51. /**
  52. * 对外开放方法
  53. * @return TagSet|Cache
  54. * @author 等风来
  55. * @email 136327134@qq.com
  56. * @date 2022/11/10
  57. */
  58. public function cacheHandler()
  59. {
  60. return $this->getCacheHandler();
  61. }
  62. /**
  63. * 缓存标签
  64. * @param null $tag
  65. * @return Tag
  66. * @author 等风来
  67. * @email 136327134@qq.com
  68. * @date 2022/11/10
  69. */
  70. public function cacheTag($tag = null)
  71. {
  72. $key = $this->cacheKey() . 'tag';
  73. $tag = $tag ? $key . ':' . $tag : $key;
  74. $redis = CacheService::redisHandler($tag);
  75. return new Tag($redis, $tag);
  76. }
  77. /**
  78. * 总缓存数据量
  79. * @return mixed
  80. */
  81. public function cacheCount()
  82. {
  83. $cacheKey = $this->cacheKey();
  84. $rds = $this->getRedisConnect();
  85. return $rds->hLen($cacheKey . 'map');
  86. }
  87. /**
  88. * 读取缓存全部数据
  89. * @return mixed
  90. */
  91. public function cacheList(string $key = '')
  92. {
  93. $cacheKey = $this->cacheKey() . $key;
  94. $rds = $this->getRedisConnect();
  95. $map = $rds->hGetAll($cacheKey . 'map');
  96. //key排序
  97. if ($map) {
  98. ksort($map);
  99. $list = array_values($map) ?: [];
  100. foreach ($list as $key => $item) {
  101. $list[$key] = $this->unserialize($item);
  102. }
  103. return $list;
  104. } else {
  105. return [];
  106. }
  107. }
  108. /**
  109. * 读取缓存分页数据
  110. * @param int $page
  111. * @param int $limit
  112. * @param string $key
  113. * @return array
  114. */
  115. public function cachePageData(int $page = 1, int $limit = 10, string $key = '')
  116. {
  117. $cacheKey = $this->cacheKey() . $key;
  118. $rds = $this->getRedisConnect();
  119. $page = max($page, 1);
  120. $limit = max($limit, 1);
  121. //先读排序
  122. $pageList = $rds->zRangeByScore($cacheKey . 'page', ($page - 1) * $limit, ($page * $limit) - 1);
  123. //再读数据
  124. $list = $rds->hMGet($cacheKey . 'map', $pageList) ?: [];
  125. if (is_array($list)) {
  126. $newList = [];
  127. foreach ($list as $value) {
  128. $newList[] = $this->unserialize($value);
  129. }
  130. $list = $newList;
  131. }
  132. $count = $rds->hLen($cacheKey . 'map');
  133. return compact('list', 'count');
  134. }
  135. /**
  136. * 单个查询数据
  137. * @param int|string $id
  138. * @return false|string|array
  139. */
  140. public function cacheInfoById($id)
  141. {
  142. $cacheKey = $this->cacheKey();
  143. $rds = $this->getRedisConnect();
  144. $value = $rds->hGet($cacheKey . 'map', $id);
  145. return $value === null ? null : $this->unserialize($value);
  146. }
  147. /**
  148. * 批量查询数据
  149. * @param $ids
  150. * @return mixed
  151. */
  152. public function cacheInfoByIds(array $ids)
  153. {
  154. $cacheKey = $this->cacheKey();
  155. $rds = $this->getRedisConnect();
  156. $arr = $rds->hMGet($cacheKey . 'map', $ids);
  157. if (is_array($arr)) {
  158. $newList = [];
  159. foreach ($arr as $key => $value) {
  160. $arr[$key] = $this->unserialize($value);
  161. }
  162. $arr = $newList;
  163. }
  164. return $arr;
  165. }
  166. /**
  167. * 更新单个缓存
  168. * @param array $info
  169. * @param null $key
  170. * @return false|mixed
  171. */
  172. public function cacheUpdate(array $info, $key = null)
  173. {
  174. $pk = $this->getPk();
  175. if ((empty($info) || !isset($info[$pk])) && !$key) {
  176. return false;
  177. }
  178. $cacheKey = $this->cacheKey();
  179. $rds = $this->getRedisConnect();
  180. $key = $key ?: $info[$pk];
  181. return $rds->hSet($cacheKey . 'map', $key, $this->serialize($info));
  182. }
  183. /**
  184. * 序列化数据
  185. * @param $value
  186. * @return string
  187. * @author 等风来
  188. * @email 136327134@qq.com
  189. * @date 2022/11/10
  190. */
  191. private function serialize($value)
  192. {
  193. try {
  194. return serialize($value);
  195. } catch (\Throwable $e) {
  196. Log::error('序列化发生错误:' . $e->getMessage());
  197. return $value;
  198. }
  199. }
  200. /**
  201. * 反序列化数据
  202. * @param $value
  203. * @return mixed
  204. * @author 等风来
  205. * @email 136327134@qq.com
  206. * @date 2022/11/10
  207. */
  208. private function unserialize($value)
  209. {
  210. try {
  211. return unserialize($value);
  212. } catch (\Throwable $e) {
  213. Log::error('反序列化发生错误:' . $e->getMessage());
  214. return $value;
  215. }
  216. }
  217. /**
  218. * @param int $id
  219. * @param $field
  220. * @param null $value
  221. * @return false|mixed
  222. * @author 等风来
  223. * @email 136327134@qq.com
  224. * @date 2022/11/1
  225. */
  226. public function cacheSaveValue(int $id, $field, $value = null)
  227. {
  228. $pk = $this->getPk();
  229. $info = $this->cacheInfoById($id);
  230. if (!$info) {
  231. $newInfo = $this->get($id);
  232. $info = $newInfo ? $newInfo->toArray() : [];
  233. }
  234. if (is_array($field)) {
  235. foreach ($field as $k => $v) {
  236. $info[$k] = $v;
  237. }
  238. } else {
  239. $info[$field] = $value;
  240. }
  241. $info[$pk] = $id;
  242. return $this->cacheUpdate($info);
  243. }
  244. /**
  245. * 不存在则写入,存在则返回
  246. * @param $key
  247. * @param callable|null $fn
  248. * @param null $default
  249. * @return array|false|mixed|string|null
  250. * @author 等风来
  251. * @email 136327134@qq.com
  252. * @date 2022/11/1
  253. */
  254. public function cacheRemember($key, callable $fn = null, $default = null)
  255. {
  256. //不开启数据缓存直接返回
  257. if (!app()->config->get('cache.is_data')) {
  258. if ($fn instanceof \Closure) {
  259. return Container::getInstance()->invokeFunction($fn);
  260. } else {
  261. return $default;
  262. }
  263. }
  264. $info = $this->cacheInfoById($key);
  265. if ((null === $info || false === $info) && is_callable($fn)) {
  266. //读取数据库缓存
  267. $newInfo = $fn();
  268. if (null !== $newInfo) {
  269. //缓存数据存在则更新
  270. $this->cacheUpdate($newInfo, $key);
  271. }
  272. $info = $newInfo;
  273. }
  274. return null !== $info ? $info : $default;
  275. }
  276. /**
  277. * 批量更新缓存
  278. * @param $list
  279. * @return false|mixed
  280. */
  281. public function cacheUpdateList(array $list, string $key = '')
  282. {
  283. if (empty($list)) {
  284. return false;
  285. }
  286. $cacheKey = $this->cacheKey() . $key;
  287. $pk = $this->getPk();
  288. $rds = $this->getRedisConnect();
  289. $map = [];
  290. foreach ($list as $item) {
  291. if (empty($item) || !isset($item[$pk])) {
  292. continue;
  293. }
  294. $map[$item[$pk]] = $this->serialize($item);
  295. }
  296. return $rds->hMSet($cacheKey . 'map', $map);
  297. }
  298. /**
  299. * 删除单条缓存
  300. * @param $id
  301. */
  302. public function cacheDelById(int $id)
  303. {
  304. $cacheKey = $this->cacheKey();
  305. $rds = $this->getRedisConnect();
  306. $rds->hDel($cacheKey . 'map', $id);
  307. $rds->zRem($cacheKey . 'page', $id);
  308. }
  309. /**
  310. * 批量删除缓存
  311. * @param $ids
  312. */
  313. public function cacheDelByIds(array $ids)
  314. {
  315. $cacheKey = $this->cacheKey();
  316. $rds = $this->getRedisConnect();
  317. foreach ($ids as $id) {
  318. $rds->hDel($cacheKey . 'map', $id);
  319. $rds->zRem($cacheKey . 'page', $id);
  320. }
  321. }
  322. /**
  323. * 创建缓存
  324. * @param array $list
  325. * @param string $key
  326. * @author 等风来
  327. * @email 136327134@qq.com
  328. * @date 2022/10/29
  329. */
  330. public function cacheCreate(array $list, string $key = '')
  331. {
  332. $pk = $this->getPk();
  333. $cacheKey = $this->cacheKey() . $key;
  334. $rds = $this->getRedisConnect();
  335. //启动事务
  336. $rds->multi();
  337. //删除旧数据
  338. $rds->del($cacheKey . 'map');
  339. $rds->del($cacheKey . 'page');
  340. //组合数据
  341. $map = [];
  342. foreach ($list as $i => $item) {
  343. $map[$item[$pk]] = $item;
  344. //存zset 排序
  345. $rds->zAdd($cacheKey . 'page', $i, $item[$pk]);
  346. }
  347. foreach ($map as $k => &$item) {
  348. $item = $this->serialize($item);
  349. }
  350. //存hmset 数据
  351. $rds->hMSet($cacheKey . 'map', $map);
  352. //执行事务
  353. $rds->exec();
  354. }
  355. protected function cacheKey()
  356. {
  357. return 'mc:' . $this->getModel()->getName() . ':';
  358. }
  359. /**
  360. *
  361. * @param $key
  362. * @return string
  363. * @author 等风来
  364. * @email 136327134@qq.com
  365. * @date 2022/11/10
  366. */
  367. public function getCacheKey($key)
  368. {
  369. return $this->cacheKey() . $key;
  370. }
  371. /**
  372. * 更新缓存
  373. * @param string $key
  374. * @param $value
  375. * @param int|null $expire
  376. * @return bool
  377. * @author 等风来
  378. * @email 136327134@qq.com
  379. * @date 2022/11/1
  380. */
  381. public function cacheStrUpdate(string $key, $value, int $expire = null)
  382. {
  383. return $this->getCacheHandler()->set($this->cacheKey() . 'str:' . $key, $value, $expire);
  384. }
  385. /**
  386. * 获取缓存
  387. * @param string $key
  388. * @return false|mixed|string
  389. * @author 等风来
  390. * @email 136327134@qq.com
  391. * @date 2022/11/1
  392. */
  393. public function cacheStrGet(string $key)
  394. {
  395. return $this->getCacheHandler()->get($this->cacheKey() . 'str:' . $key);
  396. }
  397. /**
  398. * 获取表缓存是否有数据
  399. * @return false|mixed|string
  400. * @author 等风来
  401. * @email 136327134@qq.com
  402. * @date 2022/11/1
  403. */
  404. public function cacheStrTable()
  405. {
  406. return $this->getRedisConnect()->get($this->cacheKey());
  407. }
  408. /**
  409. * 设置表缓存是否有数据
  410. * @param int $value
  411. * @return bool
  412. * @author 等风来
  413. * @email 136327134@qq.com
  414. * @date 2022/11/1
  415. */
  416. public function cacheStrSetTable(int $value = 1)
  417. {
  418. return $this->getRedisConnect()->set($this->cacheKey(), $value);
  419. }
  420. /**
  421. * 删除缓存
  422. * @param string $key
  423. * @return int
  424. * @author 等风来
  425. * @email 136327134@qq.com
  426. * @date 2022/11/1
  427. */
  428. public function cacheStrDel(string $key)
  429. {
  430. return $this->getCacheHandler()->delete($this->cacheKey() . 'str:' . $key);
  431. }
  432. /**
  433. * 获取缓存,没有则写入缓存并返回
  434. * @param string $key
  435. * @param callable|null $fn
  436. * @param int|null $expire
  437. * @param null $default
  438. * @return false|mixed|string|null
  439. * @author 等风来
  440. * @email 136327134@qq.com
  441. * @date 2022/11/1
  442. */
  443. public function cacheStrRemember(string $key, callable $fn = null, int $expire = null, $default = null)
  444. {
  445. //不开启数据缓存直接返回
  446. if (!app()->config->get('cache.is_data')) {
  447. if ($fn instanceof \Closure) {
  448. return Container::getInstance()->invokeFunction($fn);
  449. } else {
  450. return $default;
  451. }
  452. }
  453. $value = $this->cacheStrGet($key);
  454. if ((null === $value || false === $value) && is_callable($fn)) {
  455. $newValue = $fn();
  456. if (null !== $newValue) {
  457. $this->cacheStrUpdate($key, $value, $expire);
  458. }
  459. $value = $newValue;
  460. }
  461. return null !== $value ? $value : $default;
  462. }
  463. }