RedisUtils.java 16 KB

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