RedisUtils.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. package zs.payment.utils;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.beans.factory.annotation.Value;
  4. import org.springframework.data.redis.core.ZSetOperations;
  5. import org.springframework.stereotype.Repository;
  6. import redis.clients.jedis.GeoCoordinate;
  7. import redis.clients.jedis.GeoUnit;
  8. import redis.clients.jedis.Pipeline;
  9. import redis.clients.jedis.Tuple;
  10. import redis.clients.jedis.params.SetParams;
  11. import java.util.*;
  12. import java.util.concurrent.TimeUnit;
  13. import java.util.stream.Collectors;
  14. /**
  15. * 该redis主要包含支付、订单等数据相关缓存(与资讯池共用)
  16. */
  17. @Repository
  18. @Slf4j
  19. public class RedisUtils {
  20. @Value("${pay.redis.master}")
  21. private String ecoCluster;
  22. public void set(String key, String cont) {
  23. set(key, cont, 0);
  24. }
  25. public void set(String key, String cont, int seconds) {
  26. Redis.withCluster(ecoCluster, jedis -> {
  27. jedis.set(key, cont);
  28. if (seconds > 0) {
  29. jedis.expire(key, seconds);
  30. }
  31. return null;
  32. });
  33. }
  34. public String get(String key) {
  35. return Redis.withCluster(ecoCluster, jedis -> jedis.get(key));
  36. }
  37. public String getByKey(String key) {
  38. return Redis.withCluster(ecoCluster, jedis -> jedis.get(key));
  39. }
  40. /**
  41. * 判断key是否存在
  42. * @param key 键
  43. * @return 如果key存在返回true,否则返回false
  44. */
  45. public Boolean exists(String key) {
  46. return Redis.withCluster(ecoCluster, jedis -> jedis.exists(key));
  47. }
  48. public List<String> lRange(String key, long startIndex, long endIndex) {
  49. List<String> back = new ArrayList<>();
  50. if (key == null || key.isEmpty()) {
  51. return back;
  52. }
  53. Redis.withCluster(ecoCluster, jedis ->
  54. back.addAll(jedis.lrange(key, startIndex, endIndex))
  55. );
  56. return back;
  57. }
  58. public List<String> mget(List<String> keys) {
  59. List<String> back = new ArrayList<>();
  60. if (keys == null || keys.isEmpty()) {
  61. return back;
  62. }
  63. Redis.withCluster(ecoCluster, jedis ->
  64. back.addAll(jedis.mget(keys.toArray(new String[0])))
  65. );
  66. return back;
  67. }
  68. public Long del(String key) {
  69. return Redis.withCluster(ecoCluster, jedis -> jedis.del(key));
  70. }
  71. /**
  72. * 对key的值做原子递减操作(-1)
  73. * @return 递减后的值
  74. */
  75. public Long decr(String key) {
  76. return Redis.withCluster(ecoCluster, jedis -> jedis.decr(key));
  77. }
  78. public void hset(String key, String field, String cont) {
  79. hset(key, field, cont, 0);
  80. }
  81. public void hset(String key, String field, String cont, int seconds) {
  82. Redis.withCluster(ecoCluster, jedis -> {
  83. jedis.hset(key, field, cont);
  84. if (seconds > 0) {
  85. jedis.expire(key, seconds);
  86. }
  87. return null;
  88. });
  89. }
  90. public void hmset(String key, Map<String, String> hash) {
  91. hmset(key, hash, 0);
  92. }
  93. public void hmset(String key, Map<String, String> hash, int seconds) {
  94. Redis.withCluster(ecoCluster, jedis -> {
  95. jedis.hmset(key, hash);
  96. if (seconds > 0) {
  97. jedis.expire(key, seconds);
  98. }
  99. return null;
  100. });
  101. }
  102. public Long hincrBy(String key, String field, long value) {
  103. return Redis.withCluster(ecoCluster, jedis -> jedis.hincrBy(key, field, value));
  104. }
  105. public String hget(String key, String field) {
  106. return Redis.withCluster(ecoCluster, jedis -> jedis.hget(key, field));
  107. }
  108. public Map<String, String> hgetAll(String key) {
  109. return Redis.withCluster(ecoCluster, jedis -> jedis.hgetAll(key));
  110. }
  111. public void hdel(String key, String field) {
  112. Redis.withCluster(ecoCluster, jedis -> {
  113. jedis.hdel(key, field);
  114. return null;
  115. });
  116. }
  117. /**
  118. *
  119. * 添加
  120. * redis> SADD myset "one"
  121. * @param key
  122. * @param members
  123. * @return
  124. */
  125. public long sadd(String key, String... members) {
  126. return Redis.withCluster(ecoCluster, jedis -> jedis.sadd(key, members));
  127. }
  128. /**
  129. * 删除
  130. * redis> SREM myset "one"
  131. * @param key
  132. * @param members
  133. * @return
  134. */
  135. public long srem(String key,String... members){
  136. return Redis.withCluster(ecoCluster,jedis -> jedis.srem(key,members));
  137. }
  138. public Set<String> smembers(String key) {
  139. return Redis.withCluster(ecoCluster, jedis -> jedis.smembers(key));
  140. }
  141. public Boolean sismember(String key,String value){
  142. return Redis.withCluster(ecoCluster,jedis -> jedis.sismember(key,value));
  143. }
  144. public long zadd(String key, double score, String member) {
  145. return Redis.withCluster(ecoCluster, jedis -> jedis.zadd(key, score, member));
  146. }
  147. /**
  148. * 向有序集合批量添加元素(使用 Tuple 集合)
  149. * @param key 键
  150. * @param tuples 元组集合(包含分数和成员)
  151. * @return 成功添加的数量
  152. */
  153. public Long zadd(String key, Set<ZSetOperations.TypedTuple<String>> tuples) {
  154. if (tuples == null || tuples.isEmpty()) {
  155. return 0L;
  156. }
  157. long result = 0L;
  158. for (ZSetOperations.TypedTuple<String> tuple : tuples) {
  159. result=result+ Redis.withCluster(ecoCluster, jedis -> jedis.zadd(key, tuple.getScore(),tuple.getValue()));
  160. }
  161. return result;
  162. }
  163. // /**
  164. // * 通过管道模式一次性添加多个值
  165. // *
  166. // * @param key
  167. // * @param list
  168. // */
  169. // public void zaddWithPipeline(String key, List<?> list) {
  170. // Redis.withCluster(ecoCluster, jedis -> {
  171. // Pipeline pipeline = jedis.pipelined();
  172. // for (Object item : list) {
  173. // double score = Double.parseDouble(((Map<?, ?>) item).get("userId").toString());
  174. // jedis.zadd(key, score, Strings.toJson(item));
  175. // }
  176. // pipeline.syncAndReturnAll();
  177. // });
  178. // }
  179. public long llen(String key) {
  180. return Redis.withCluster(ecoCluster, jedis -> jedis.llen(key));
  181. }
  182. public List<String> lrangeList(String key, int start, int end) {
  183. List<String> result = Redis.withCluster(ecoCluster, jedis -> jedis.lrange(key, start, end));
  184. return result != null ? result : new ArrayList<>();
  185. }
  186. public void lpush(String key, String... strings) {
  187. Redis.withCluster(ecoCluster, jedis -> {
  188. jedis.lpush(key, strings);
  189. return null;
  190. });
  191. }
  192. public long rpush(String key, String value) {
  193. return Redis.withCluster(ecoCluster, jedis -> jedis.rpush(key, value));
  194. }
  195. public String rpop(String key) {
  196. return Redis.withCluster(ecoCluster, jedis -> jedis.rpop(key));
  197. }
  198. public String lpop(String key) {
  199. return Redis.withCluster(ecoCluster, jedis -> jedis.lpop(key));
  200. }
  201. public long zrem(String key, String member) {
  202. return Redis.withCluster(ecoCluster, jedis -> jedis.zrem(key, member));
  203. }
  204. /**
  205. *
  206. * 返回有序集的元素个数(对应 redisTemplate.opsForZSet().size())
  207. * @param key
  208. * @return
  209. */
  210. public long zcard(String key) {
  211. return Redis.withCluster(ecoCluster, jedis -> jedis.zcard(key));
  212. }
  213. public Double zscore(String key, String member) {
  214. return Redis.withCluster(ecoCluster, jedis -> jedis.zscore(key, member));
  215. }
  216. /**
  217. * 倒序(从大到小)获取指定区间内的数据
  218. *
  219. * @param key
  220. * @param start
  221. * @param end
  222. * @return
  223. */
  224. public Set<String> zrevrange(String key, long start, long end) {
  225. return Redis.withCluster(ecoCluster, jedis -> jedis.zrevrange(key, start, end));
  226. }
  227. /**
  228. * 正序(从小到大)获取指定区间内的数据
  229. *
  230. * @param key
  231. * @param start
  232. * @param end
  233. * @return
  234. */
  235. public Set<String> zrange(String key, long start, long end) {
  236. return Redis.withCluster(ecoCluster, jedis -> jedis.zrange(key, start, end));
  237. }
  238. /**
  239. * 根据score值,倒序(从大到小)获取指定区间内的数据
  240. *
  241. * @param key
  242. * @param score
  243. * @param psize
  244. * @return
  245. */
  246. public Set<String> zrevrangeByScore(String key, String score, Integer psize) {
  247. return Redis.withCluster(ecoCluster, jedis -> jedis.zrevrangeByScore(key, "(" + score, "-inf", 0, psize));
  248. }
  249. /**
  250. * 获取score值介于score1和score2之间的数据
  251. *
  252. * @param key
  253. * @param score1
  254. * @param score2
  255. * @return
  256. */
  257. public Set<String> zrangeByScore(String key, String score1, String score2) {
  258. return Redis.withCluster(ecoCluster, jedis -> jedis.zrangeByScore(key, score1, score2));
  259. }
  260. /**
  261. * 设置自增长
  262. *
  263. * @param key
  264. * @return
  265. */
  266. public synchronized long setIncyBy(String key) {
  267. return setIncyBy(key, 1L, 0);
  268. }
  269. /**
  270. * 设置自增长
  271. *
  272. * @param key
  273. * @param num
  274. * @return
  275. */
  276. public synchronized long setIncyBy(String key, long num) {
  277. return setIncyBy(key, num, 0);
  278. }
  279. /**
  280. * 设置自增长
  281. *
  282. * @param key
  283. * @param num
  284. * @param seconds
  285. * @return
  286. */
  287. public synchronized long setIncyBy(String key, long num, int seconds) {
  288. return Redis.withCluster(ecoCluster, jedis -> {
  289. long result = jedis.incrBy(key, num);
  290. if (seconds > 0) {
  291. jedis.expire(key, seconds);
  292. }
  293. return result;
  294. });
  295. }
  296. public long setIncy(String key) {
  297. return Redis.withCluster(ecoCluster, jedis -> jedis.incr(key));
  298. }
  299. public long setDecy(String key) {
  300. return Redis.withCluster(ecoCluster, jedis -> jedis.decr(key));
  301. }
  302. /**
  303. * 按分数从小到大删除指定区域的数据 (对应redisTemplate.opsForZSet().removeRange(key,begin,end)))
  304. *
  305. * @param key
  306. * @param start
  307. * @param end
  308. * @return
  309. */
  310. public long zremrangeByRank(String key, long start, long end) {
  311. return Redis.withCluster(ecoCluster, jedis -> jedis.zremrangeByRank(key, start, end));
  312. }
  313. /**
  314. * setnx实现简单的分布式锁
  315. *
  316. * @param key
  317. * @param value
  318. * @return
  319. */
  320. public long setnx(String key, String value) {
  321. return setnx(key, value, 0);
  322. }
  323. /**
  324. * setnx实现简单的分布式锁
  325. *
  326. * @param key
  327. * @param value
  328. * @param seconds
  329. * @return
  330. */
  331. public long setnx(String key, String value, int seconds) {
  332. return Redis.withCluster(ecoCluster, jedis -> {
  333. long result = jedis.setnx(key, value);
  334. if (result == 1 && seconds > 0) {
  335. jedis.expire(key, seconds);
  336. }
  337. return result;
  338. });
  339. }
  340. /**
  341. * SET NX EX 原子命令:仅当Key不存在时设置值,并设置过期时间
  342. * 用于分布式锁的获取
  343. *
  344. * @param key 锁的键
  345. * @param value 锁的值(通常是实例ID或服务ID)
  346. * @param seconds 过期时间(秒)
  347. * @return true 表示成功获得锁,false 表示锁已被占用
  348. */
  349. public boolean setIfAbsent(String key, String value, int seconds) {
  350. String result = Redis.withCluster(ecoCluster, jedis -> {
  351. // 使用 SET key value NX EX seconds 原子命令
  352. // NX: Only set the key if it does not already exist
  353. // EX: Set the specified expire time, in seconds
  354. SetParams params = new SetParams().nx().ex(seconds);
  355. return jedis.set(key, value, params);
  356. });
  357. // 返回 "OK" 表示成功,null 表示键已存在
  358. return "OK".equals(result);
  359. }
  360. /**
  361. * 根据前缀获取所有的key
  362. * 例如:pro_*
  363. */
  364. public Set<String> getListKey(String prefix) {
  365. return Redis.withCluster(ecoCluster, jedis -> jedis.keys(prefix.concat("*")));
  366. }
  367. public long geoAdd(String key, double lng, double lat, String member) {
  368. return Redis.withCluster(ecoCluster, jedis -> jedis.geoadd(key, lng, lat, member));
  369. }
  370. public double geoDist(String key, String member1, String member2) {
  371. Double result = Redis.withCluster(ecoCluster, jedis -> jedis.geodist(key, member1, member2, GeoUnit.KM));
  372. return result != null ? result : 0.0;
  373. }
  374. public List<Map<String, Object>> geoPos(String key, String... members) {
  375. List<GeoCoordinate> coordinates = Redis.withCluster(ecoCluster, jedis -> jedis.geopos(key, members));
  376. List<Map<String, Object>> coordinateList = new ArrayList<>();
  377. if (coordinates != null && !coordinates.isEmpty()) {
  378. for (GeoCoordinate coord : coordinates) {
  379. Map<String, Object> location = new HashMap<>();
  380. location.put("lng", coord.getLongitude());
  381. location.put("lat", coord.getLatitude());
  382. coordinateList.add(location);
  383. }
  384. }
  385. return coordinateList;
  386. }
  387. /**
  388. * 设置key的过期时间(对应 redisTemplate.expire())
  389. * @param key 键
  390. * @param timeout 过期时间
  391. * @param unit 时间单位
  392. * @return 是否设置成功
  393. */
  394. public long ttl(String key) {
  395. return Redis.withCluster(ecoCluster, jedis -> jedis.ttl(key));
  396. }
  397. public Boolean expire(String key, long timeout, TimeUnit unit) {
  398. return Redis.withCluster(ecoCluster, jedis -> {
  399. // 转换为秒
  400. long seconds = unit.toSeconds(timeout);
  401. if (seconds > Integer.MAX_VALUE) {
  402. log.warn("过期时间超过Integer最大值,将使用最大值: {}", Integer.MAX_VALUE);
  403. seconds = Integer.MAX_VALUE;
  404. }
  405. jedis.expire(key, (int) seconds);
  406. return true;
  407. });
  408. }
  409. public void set(String key, String cont, int timeout, TimeUnit unit) {
  410. Redis.withCluster(ecoCluster, jedis -> {
  411. // 转换为秒
  412. long seconds = unit.toSeconds(timeout);
  413. if (seconds > Integer.MAX_VALUE) {
  414. seconds = Integer.MAX_VALUE;
  415. }
  416. jedis.set(key, cont);
  417. if (seconds > 0) {
  418. jedis.expire(key, seconds);
  419. }
  420. return null;
  421. });
  422. }
  423. /**
  424. * 获取有序集合中指定排名范围内的成员及其分数(按分数从高到低排序)
  425. * 对应 redisTemplate.opsForZSet().reverseRangeWithScores()
  426. *
  427. * @param key 键
  428. * @param start 起始索引(从0开始,包含)
  429. * @param end 结束索引(包含,-1表示最后一个)
  430. * @return 包含成员和分数的元组集合
  431. */
  432. public Set<ZSetOperations.TypedTuple<String>> zReverseRangeWithScores(String key, long start, long end) {
  433. Set<Tuple> tuples = Redis.withCluster(ecoCluster, jedis ->
  434. jedis.zrevrangeWithScores(key, start, end));
  435. return tuples.stream()
  436. .map(tuple -> ZSetOperations.TypedTuple.of(
  437. tuple.getElement(), // 获取元素
  438. tuple.getScore() // 获取分数
  439. ))
  440. .collect(Collectors.toSet());
  441. }
  442. /**
  443. * 使用 Pipeline 批量设置字符串键值对(高性能,适合大量数据)
  444. * @param map 包含多个键值对的Map
  445. */
  446. public void multiSetWithPipeline(Map<String, String> map,int timeout, TimeUnit unit) {
  447. if (map == null || map.isEmpty()) {
  448. return;
  449. }
  450. Redis.withCluster(ecoCluster, jedis -> {
  451. // 创建管道
  452. Pipeline pipeline = jedis.pipelined();
  453. // 将所有set命令添加到管道
  454. for (Map.Entry<String, String> entry : map.entrySet()) {
  455. pipeline.set(entry.getKey(), entry.getValue());
  456. pipeline.expire(entry.getKey(), unit.toSeconds(timeout));
  457. }
  458. // 批量执行
  459. pipeline.sync();
  460. return null;
  461. });
  462. }
  463. public void hmset(String key, Map<String, String> hash, int timeout, TimeUnit unit) {
  464. Redis.withCluster(ecoCluster, jedis -> {
  465. jedis.hmset(key, hash);
  466. if (timeout > 0) {
  467. jedis.expire(key, unit.toSeconds(timeout));
  468. }
  469. return null;
  470. });
  471. }
  472. }