RedisUtils.java 16 KB

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