CacheService.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace qiniu\services;
  12. use Redis;
  13. use think\cache\TagSet;
  14. use think\facade\Cache as CacheStatic;
  15. /**
  16. * crmeb 缓存类
  17. * Class CacheService
  18. * @package crmeb\services
  19. * @mixin Redis
  20. */
  21. class CacheService
  22. {
  23. /**
  24. * 标签名
  25. * @var string
  26. */
  27. protected static $globalCacheName = '_cached_qiniu_1515146130';
  28. protected static $redisQueueKey = [];
  29. /**
  30. * 过期时间
  31. * @var int
  32. */
  33. protected static $expire;
  34. /**
  35. * 获取缓存过期时间
  36. * @param int|null $expire
  37. * @return int
  38. */
  39. protected static function getExpire(int $expire = null): int
  40. {
  41. if (self::$expire) {
  42. return (int)self::$expire;
  43. }
  44. $expire = !is_null($expire) ? $expire : SystemConfigService::get('cache_config', null, true);
  45. if (!is_int($expire))
  46. $expire = (int)$expire;
  47. return self::$expire = $expire;
  48. }
  49. /**
  50. * 判断缓存是否存在
  51. * @param string $name
  52. * @return bool
  53. * @throws \Psr\SimpleCache\InvalidArgumentException
  54. */
  55. public static function has(string $name): bool
  56. {
  57. try {
  58. return CacheStatic::has($name);
  59. } catch (\Throwable $e) {
  60. return false;
  61. }
  62. }
  63. /**
  64. * 写入缓存
  65. * @param string $name 缓存名称
  66. * @param mixed $value 缓存值
  67. * @param int $expire 缓存时间,为0读取系统缓存时间
  68. * @return bool
  69. */
  70. public static function set(string $name, $value, int $expire = null): bool
  71. {
  72. try {
  73. return self::handler()->set($name, $value, $expire ?? self::getExpire($expire));
  74. } catch (\Throwable $e) {
  75. return false;
  76. }
  77. }
  78. /**
  79. * 如果不存在则写入缓存
  80. * @param string $name
  81. * @param bool $default
  82. * @return mixed
  83. */
  84. public static function get(string $name, $default = false, int $expire = null)
  85. {
  86. try {
  87. return self::handler()->remember($name, $default, $expire ?? self::getExpire($expire));
  88. } catch (\Throwable $e) {
  89. try {
  90. if (is_callable($default)) {
  91. return $default();
  92. } else {
  93. return $default;
  94. }
  95. } catch (\Throwable $e) {
  96. return null;
  97. }
  98. }
  99. }
  100. /**
  101. * 如果不存在则写入缓存
  102. * @param string $name
  103. * @param bool $default
  104. * @return mixed
  105. */
  106. public static function remember(string $name, $default = false, int $expire = null)
  107. {
  108. try {
  109. return self::handler()->remember($name, $default, $expire ?? self::getExpire($expire));
  110. } catch (\Throwable $e) {
  111. try {
  112. if (is_callable($default)) {
  113. return $default();
  114. } else {
  115. return $default;
  116. }
  117. } catch (\Throwable $e) {
  118. return null;
  119. }
  120. }
  121. }
  122. /**
  123. * 删除缓存
  124. * @param string $name
  125. * @return bool
  126. * @throws \Psr\SimpleCache\InvalidArgumentException
  127. */
  128. public static function delete(string $name)
  129. {
  130. return CacheStatic::delete($name);
  131. }
  132. /**
  133. * 缓存句柄
  134. *
  135. * @return TagSet|CacheStatic
  136. */
  137. public static function handler(?string $cacheName = null)
  138. {
  139. return CacheStatic::tag($cacheName ?: self::$globalCacheName);
  140. }
  141. /**
  142. * 清空缓存池
  143. * @return bool
  144. */
  145. public static function clear()
  146. {
  147. return self::handler()->clear();
  148. }
  149. /**
  150. * Redis缓存句柄
  151. *
  152. * @return TagSet|\think\cache\Driver
  153. */
  154. public static function redisHandler(string $type = null)
  155. {
  156. if ($type) {
  157. return CacheStatic::store('redis')->tag($type);
  158. } else {
  159. return CacheStatic::store('redis');
  160. }
  161. }
  162. /**
  163. * 放入令牌桶
  164. * @param string $key
  165. * @param array $value
  166. * @param string $type
  167. * @return bool
  168. */
  169. public static function setTokenBucket(string $key, $value, $expire = null, string $type = 'admin')
  170. {
  171. try {
  172. $redisCahce = self::redisHandler($type);
  173. return $redisCahce->set($key, $value, $expire);
  174. } catch (\Throwable $e) {
  175. return false;
  176. }
  177. }
  178. /**
  179. * 清除所有令牌桶
  180. * @param string $type
  181. * @return bool
  182. */
  183. public static function clearTokenAll(string $type = 'admin')
  184. {
  185. try {
  186. return self::redisHandler($type)->clear();
  187. } catch (\Throwable $e) {
  188. return false;
  189. }
  190. }
  191. /**
  192. * 清除令牌桶
  193. * @param string $type
  194. * @return bool
  195. */
  196. public static function clearToken(string $key)
  197. {
  198. try {
  199. return self::redisHandler()->delete($key);
  200. } catch (\Throwable $e) {
  201. return false;
  202. }
  203. }
  204. /**
  205. * 查看令牌是否存在
  206. * @param string $key
  207. * @return bool
  208. */
  209. public static function hasToken(string $key)
  210. {
  211. try {
  212. return self::redisHandler()->has($key);
  213. } catch (\Throwable $e) {
  214. return false;
  215. }
  216. }
  217. /**
  218. * 获取token令牌桶
  219. * @param string $key
  220. * @return mixed|null
  221. * @throws \Psr\SimpleCache\InvalidArgumentException
  222. */
  223. public static function getTokenBucket(string $key)
  224. {
  225. try {
  226. return self::redisHandler()->get($key, null);
  227. } catch (\Throwable $e) {
  228. return null;
  229. }
  230. }
  231. /**
  232. * 获取指定分数区间的成员
  233. * @param $key
  234. * @param int $start
  235. * @param int $end
  236. * @param array $options
  237. * @return mixed
  238. */
  239. public static function zRangeByScore($key, $start = '-inf', $end = '+inf', array $options = [])
  240. {
  241. return self::redisHandler()->zRangeByScore($key, $start, $end, $options);
  242. }
  243. /**
  244. * 设置redis入库队列
  245. * @param string $unique
  246. * @param int $number
  247. * @param int $type
  248. * @param bool $isPush true :重置 false:累加
  249. * @return bool
  250. */
  251. public static function setStock(string $unique, int $number, int $type = 1, bool $isPush = true)
  252. {
  253. if (!$unique || !$number) return false;
  254. $name = (self::$redisQueueKey[$type] ?? '') . '_' . $type . '_' . $unique;
  255. /** @var self $cache */
  256. $cache = self::redisHandler();
  257. $res = true;
  258. if ($isPush) {
  259. $cache->del($name);
  260. }
  261. $data = [];
  262. for ($i = 1; $i <= $number; $i++) {
  263. $data[] = $i;
  264. }
  265. $res = $res && $cache->lPush($name, ...$data);
  266. return $res;
  267. }
  268. /**
  269. * 弹出redis队列中的库存条数
  270. * @param string $unique
  271. * @param int $number
  272. * @param int $type
  273. * @return bool
  274. */
  275. public static function popStock(string $unique, int $number, int $type = 1)
  276. {
  277. if (!$unique || !$number) return false;
  278. $name = (self::$redisQueueKey[$type] ?? '') . '_' . $type . '_' . $unique;
  279. /** @var self $cache */
  280. $cache = self::redisHandler();
  281. $res = true;
  282. if ($number > $cache->lLen($name)) {
  283. return false;
  284. }
  285. for ($i = 1; $i <= $number; $i++) {
  286. $res = $res && $cache->lPop($name);
  287. }
  288. return $res;
  289. }
  290. /**
  291. * 是否有库存|返回库存
  292. * @param string $unique
  293. * @param int $number
  294. * @param int $type
  295. * @return bool
  296. */
  297. public static function checkStock(string $unique, int $number = 0, int $type = 1)
  298. {
  299. $name = (self::$redisQueueKey[$type] ?? '') . '_' . $type . '_' . $unique;
  300. if ($number) {
  301. return self::redisHandler()->lLen($name) >= $number;
  302. } else {
  303. return self::redisHandler()->lLen($name);
  304. }
  305. }
  306. /**
  307. * 检查锁
  308. * @param string $key
  309. * @param int $timeout
  310. * @return bool
  311. * @author 等风来
  312. * @email 136327134@qq.com
  313. * @date 2022/11/22
  314. */
  315. public static function setMutex(string $key, int $timeout = 10)
  316. {
  317. $curTime = time();
  318. $readMutexKey = "redis:mutex:{$key}";
  319. $mutexRes = self::redisHandler()->handler()->setnx($readMutexKey, $curTime + $timeout);
  320. if ($mutexRes) {
  321. return true;
  322. }
  323. //就算意外退出,下次进来也会检查key,防止死锁
  324. $time = self::redisHandler()->handler()->get($readMutexKey);
  325. if ($curTime > $time) {
  326. self::redisHandler()->handler()->del($readMutexKey);
  327. return self::redisHandler()->handler()->setnx($readMutexKey, $curTime + $timeout);
  328. }
  329. return false;
  330. }
  331. /**
  332. * 删除锁
  333. * @param string $key
  334. * @author 等风来
  335. * @email 136327134@qq.com
  336. * @date 2022/11/22
  337. */
  338. public static function delMutex(string $key)
  339. {
  340. $readMutexKey = "redis:mutex:{$key}";
  341. self::redisHandler()->handler()->del($readMutexKey);
  342. }
  343. /**
  344. * 数据库锁
  345. * @param $key
  346. * @param $fn
  347. * @param int $ex
  348. * @return bool|mixed
  349. */
  350. public static function lock($key, $fn = [], int $ex = 10)
  351. {
  352. $service = app()->make(LockService::class);
  353. if ($fn instanceof \Closure) {
  354. return $service->exec($key, $fn, $ex);
  355. } else {
  356. return $service->lock($key, 1, $ex);
  357. }
  358. }
  359. /**
  360. * 销毁锁
  361. * @param $key
  362. * @return bool
  363. */
  364. public static function unLock($key)
  365. {
  366. return app()->make(LockService::class)->unlock($key);
  367. }
  368. /**
  369. * 魔术方法
  370. * @param $name
  371. * @param $arguments
  372. * @return mixed
  373. */
  374. public static function __callStatic($name, $arguments)
  375. {
  376. return self::redisHandler()->{$name}(...$arguments);
  377. }
  378. /**
  379. * 魔术方法
  380. * @param $name
  381. * @param $arguments
  382. * @return mixed
  383. */
  384. public function __call($name, $arguments)
  385. {
  386. return self::redisHandler()->{$name}(...$arguments);
  387. }
  388. }