RedisUtil.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. package com.ljsd.redis;
  2. import com.ljsd.util.BaseGlobal;
  3. import com.ljsd.util.TimeUtil;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import redis.clients.jedis.Jedis;
  7. import redis.clients.jedis.JedisPool;
  8. import redis.clients.jedis.JedisPoolConfig;
  9. import java.util.*;
  10. public class RedisUtil {
  11. private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);
  12. private static int MAX_TRY_TIMES = 3; //最大尝试次数,保障获取/存储成功
  13. private static int FAILED_SLEEP = 2; //每次失败最大停顿时间
  14. private JedisPool jedisPool;//非切片连接池
  15. protected void init() {
  16. // 池基本配置
  17. JedisPoolConfig config = new JedisPoolConfig();
  18. Properties properties = BaseGlobal.getInstance().properties;
  19. config.setMaxTotal(Integer.parseInt(properties.getProperty("redis_maxTotal")));
  20. config.setMinIdle(Integer.parseInt(properties.getProperty("redis_minIdle")));
  21. config.setMaxWaitMillis(Integer.parseInt(properties.getProperty("redis_maxWaitMillis")));
  22. config.setMaxIdle(Integer.parseInt(properties.getProperty("redis_maxIdle")));
  23. config.setTestOnBorrow(Boolean.parseBoolean(properties.getProperty("redis_testOnBorrow")));
  24. if (properties.getProperty("redis_password") ==null || properties.getProperty("redis_password").isEmpty()){
  25. jedisPool = new JedisPool(config, properties.getProperty("redis_host"), Integer.parseInt(properties.getProperty("redis_port")),0);
  26. }else{
  27. jedisPool = new JedisPool(config, properties.getProperty("redis_host"), Integer.parseInt(properties.getProperty("redis_port")),0,properties.getProperty("redis_password"));
  28. }
  29. }
  30. /***************************************普通键值对操作***************************************/
  31. //设置键值
  32. protected void set(final String key, String value) throws Exception {
  33. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  34. Jedis jedis = jedisPool.getResource();
  35. try {
  36. jedis.set(key, value);
  37. return;
  38. } catch (Exception e) {
  39. LOGGER.error("set->i={}: key={}, value={}", i, key, value, e);
  40. TimeUtil.sleep(FAILED_SLEEP);
  41. } finally {
  42. jedis.close();
  43. }
  44. }
  45. throw new Exception("RedisUtil::set exception");
  46. }
  47. //设置键值,带过期时间
  48. protected void setex(final String key, final int seconds, final String value) throws Exception {
  49. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  50. Jedis jedis = jedisPool.getResource();
  51. try {
  52. jedis.setex(key, seconds, value);
  53. return;
  54. } catch (Exception e) {
  55. LOGGER.error("setex->i={},key={},value={},seconds={}", i, key, value, seconds, e);
  56. TimeUtil.sleep(FAILED_SLEEP);
  57. } finally {
  58. jedis.close();
  59. }
  60. }
  61. throw new Exception("RedisUtil::setex exception");
  62. }
  63. //取得键的值
  64. protected String get(final String key) throws Exception {
  65. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  66. Jedis jedis = jedisPool.getResource();
  67. try {
  68. return jedis.get(key);
  69. } catch (Exception e) {
  70. LOGGER.error("get->i={},key={}", i, key, e);
  71. TimeUtil.sleep(FAILED_SLEEP);
  72. } finally {
  73. jedis.close();
  74. }
  75. }
  76. throw new Exception("RedisUtil::get exception");
  77. }
  78. //删除键值
  79. protected void del(String key) throws Exception {
  80. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  81. Jedis jedis = jedisPool.getResource();
  82. try {
  83. jedis.del(key);
  84. return;
  85. } catch (Exception e) {
  86. LOGGER.error("del->i={},key={}", i, key, e);
  87. TimeUtil.sleep(FAILED_SLEEP);
  88. } finally {
  89. jedis.close();
  90. }
  91. }
  92. throw new Exception("RedisUtil::del exception");
  93. }
  94. //删除键值
  95. protected boolean exists(String key) throws Exception {
  96. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  97. Jedis jedis = jedisPool.getResource();
  98. try {
  99. return jedis.exists(key);
  100. } catch (Exception e) {
  101. LOGGER.error("exists->i={},key={}", i, key, e);
  102. TimeUtil.sleep(FAILED_SLEEP);
  103. } finally {
  104. jedis.close();
  105. }
  106. }
  107. throw new Exception("RedisUtil::exists exception");
  108. }
  109. //设置过期时间
  110. protected Long expire(final String key, final int seconds) throws Exception {
  111. if (seconds <= 0) {
  112. return 0L;
  113. }
  114. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  115. Jedis jedis = jedisPool.getResource();
  116. try {
  117. return jedis.expire(key, seconds);
  118. } catch (Exception e) {
  119. LOGGER.error("expire->i={},key={},seconds={}", i, key, seconds, e);
  120. TimeUtil.sleep(FAILED_SLEEP);
  121. } finally {
  122. jedis.close();
  123. }
  124. }
  125. throw new Exception("RedisUtil::del exception");
  126. }
  127. /***************************************以下是map操作***************************************/
  128. //添加redis map
  129. protected void hmset(final String key, final Map<String, String> hash, int seconds) throws Exception {
  130. int i;
  131. for (i = 0; i < MAX_TRY_TIMES; i++) {
  132. Jedis jedis = jedisPool.getResource();
  133. try {
  134. jedis.hmset(key, hash);
  135. break;
  136. } catch (Exception e) {
  137. LOGGER.error("hmset->i={},key={}", i, key, e);
  138. TimeUtil.sleep(FAILED_SLEEP);
  139. } finally {
  140. jedis.close();
  141. }
  142. }
  143. expire(key, seconds);
  144. if (i >= MAX_TRY_TIMES) {
  145. throw new Exception("RedisUtil::hmset exception");
  146. }
  147. }
  148. //取得主key下的所有子key
  149. protected Set<String> hkeys(final String key) throws Exception {
  150. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  151. Jedis jedis = jedisPool.getResource();
  152. try {
  153. Set<String> keySet = jedis.hkeys(key);
  154. return keySet;
  155. } catch (Exception e) {
  156. LOGGER.error("hkeys->i={},key={}", i, key, e);
  157. TimeUtil.sleep(FAILED_SLEEP);
  158. } finally {
  159. jedis.close();
  160. }
  161. }
  162. throw new Exception("RedisUtil::hkeys exception");
  163. }
  164. //设置redis map一个键值 下的子key下的值
  165. protected void hset(final String key, final String field, final String value, int seconds) throws Exception {
  166. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  167. Jedis jedis = jedisPool.getResource();
  168. try {
  169. jedis.hset(key, field, value);
  170. return;
  171. } catch (Exception e) {
  172. LOGGER.error("hset->i={},key={},field={},value={}", i, key, field, value, e);
  173. TimeUtil.sleep(FAILED_SLEEP);
  174. } finally {
  175. jedis.close();
  176. }
  177. }
  178. expire(key, seconds);
  179. throw new Exception("RedisUtil::hset exception");
  180. }
  181. //取redis map全部数据的直接方法
  182. protected Map<String, String> hgetAll(final String key) throws Exception {
  183. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  184. Jedis jedis = jedisPool.getResource();
  185. try {
  186. return jedis.hgetAll(key);
  187. } catch (Exception e) {
  188. LOGGER.error("hgetAll->i={},key={}", i, key, e);
  189. TimeUtil.sleep(FAILED_SLEEP);
  190. } finally {
  191. jedis.close();
  192. }
  193. }
  194. throw new Exception("RedisUtil::hgetAll exception");
  195. }
  196. //获取redis map下一个key的值的直接方法
  197. protected List<String> hmget(final String key, final String... fields) throws Exception {
  198. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  199. Jedis jedis = jedisPool.getResource();
  200. try {
  201. return jedis.hmget(key, fields);
  202. } catch (Exception e) {
  203. LOGGER.error("hmget->i={},key={}", i, key, e);
  204. TimeUtil.sleep(FAILED_SLEEP);
  205. } finally {
  206. jedis.close();
  207. }
  208. }
  209. throw new Exception("RedisUtil::hmget exception");
  210. }
  211. //删除子key
  212. protected void hdel(final String key, final String... fields) throws Exception {
  213. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  214. Jedis jedis = jedisPool.getResource();
  215. try {
  216. jedis.hdel(key, fields);
  217. return;
  218. } catch (Exception e) {
  219. LOGGER.error("hdel->i={},key={},fields={}", i, key, fields, e);
  220. TimeUtil.sleep(FAILED_SLEEP);
  221. } finally {
  222. jedis.close();
  223. }
  224. }
  225. throw new Exception("RedisUtil::hdel exception");
  226. }
  227. /***************************************以下是list操作***************************************/
  228. //添加list数据
  229. protected long lpush(final String key, final int seconds, final String... strings) throws Exception {
  230. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  231. Jedis jedis = jedisPool.getResource();
  232. try {
  233. return jedis.lpush(key, strings);
  234. } catch (Exception e) {
  235. LOGGER.error("lpush->i={},key={},value={}", i, key, e);
  236. TimeUtil.sleep(FAILED_SLEEP);
  237. } finally {
  238. jedis.close();
  239. }
  240. }
  241. expire(key, seconds);
  242. throw new Exception("RedisUtil::lpush exception");
  243. }
  244. protected void ltrim(final String key, final int start, final int end) throws Exception {
  245. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  246. Jedis jedis = jedisPool.getResource();
  247. try {
  248. jedis.ltrim(key, start, end);
  249. return;
  250. } catch (Exception e) {
  251. LOGGER.error("lpush->i={},key={},value={}", i, key, e);
  252. TimeUtil.sleep(FAILED_SLEEP);
  253. } finally {
  254. jedis.close();
  255. }
  256. }
  257. throw new Exception("RedisUtil::ltrim exception");
  258. }
  259. //删除元素
  260. protected void lrem(final String key, final long count, final String value) throws Exception {
  261. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  262. Jedis jedis = jedisPool.getResource();
  263. try {
  264. jedis.lrem(key, count, value);
  265. return;
  266. } catch (Exception e) {
  267. LOGGER.error("lrem->i={},key={},count={},value={}", i, key, count, value, e);
  268. TimeUtil.sleep(FAILED_SLEEP);
  269. } finally {
  270. jedis.close();
  271. }
  272. }
  273. throw new Exception("RedisUtil::lrem exception");
  274. }
  275. //移除最好的元素
  276. protected String rpop(final String key) throws Exception {
  277. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  278. Jedis jedis = jedisPool.getResource();
  279. try {
  280. return jedis.rpop(key);
  281. } catch (Exception e) {
  282. LOGGER.error("rpop->i={},key={}", i, key, e);
  283. TimeUtil.sleep(FAILED_SLEEP);
  284. } finally {
  285. jedis.close();
  286. }
  287. }
  288. throw new Exception("RedisUtil::rpop exception");
  289. }
  290. //取得指定范围的元素
  291. protected List<String> lrange(final String key, final long start, final long end) throws Exception {
  292. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  293. Jedis jedis = jedisPool.getResource();
  294. try {
  295. return jedis.lrange(key, start, end);
  296. } catch (Exception e) {
  297. LOGGER.error("lrange->i={},key={},start={},end={}", i, key, start, end, e);
  298. TimeUtil.sleep(FAILED_SLEEP);
  299. } finally {
  300. jedis.close();
  301. }
  302. }
  303. throw new Exception("RedisUtil::lrange exception");
  304. }
  305. //取得list的长度
  306. protected Long llen(final String key) throws Exception {
  307. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  308. Jedis jedis = jedisPool.getResource();
  309. try {
  310. return jedis.llen(key);
  311. } catch (Exception e) {
  312. LOGGER.error("llen->i={},key={}", i, key, e);
  313. TimeUtil.sleep(FAILED_SLEEP);
  314. } finally {
  315. jedis.close();
  316. }
  317. }
  318. throw new Exception("RedisUtil::llen exception");
  319. }
  320. //自增
  321. protected Long incr(final String key) throws Exception {
  322. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  323. Jedis jedis = jedisPool.getResource();
  324. try {
  325. return jedis.incr(key);
  326. } catch (Exception e) {
  327. LOGGER.error("incr->i={},key={}", i, key, e);
  328. TimeUtil.sleep(FAILED_SLEEP);
  329. } finally {
  330. jedis.close();
  331. }
  332. }
  333. throw new Exception("RedisUtil::incr exception");
  334. }
  335. private static final String LOCK_SUCCESS = "OK";
  336. private static final String SET_IF_NOT_EXIST = "NX";
  337. private static final String SET_WITH_EXPIRE_TIME = "PX";
  338. /**
  339. * 尝试获取分布式锁
  340. *
  341. * @param lockKey 锁
  342. * @param requestId 请求标识
  343. * @param expireTime 超期时间,理论上应该比较短,一次请求在500毫秒内即可完成,因此过期时间不应大于1秒
  344. * @return 是否获取成功
  345. */
  346. protected boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) throws Exception {
  347. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  348. Jedis jedis = jedisPool.getResource();
  349. try {
  350. String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
  351. if (LOCK_SUCCESS.equals(result)) {
  352. return true;
  353. }
  354. LOGGER.error("tryGetDistributedLock->i={},key={};failed", i, lockKey);
  355. TimeUtil.sleep(200); //理论上锁冲突的几率很小,如果连续三次加锁失败,直接抛出异常
  356. } catch (Exception e) {
  357. LOGGER.error("tryGetDistributedLock->i={},key={}", i, lockKey, e);
  358. TimeUtil.sleep(FAILED_SLEEP);
  359. } finally {
  360. jedis.close();
  361. }
  362. }
  363. throw new Exception("RedisUtil::tryGetDistributedLock exception");
  364. }
  365. private static final Long RELEASE_SUCCESS = 1L;
  366. /**
  367. * 释放分布式锁
  368. *
  369. * @param lockKey 锁
  370. * @param requestId 请求标识
  371. * @return 是否释放成功
  372. */
  373. protected boolean releaseDistributedLock(String lockKey, String requestId) throws Exception {
  374. for (int i = 0; i < MAX_TRY_TIMES; i++) {
  375. Jedis jedis = jedisPool.getResource();
  376. try {
  377. String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
  378. Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
  379. if (RELEASE_SUCCESS.equals(result)) {
  380. return true;
  381. }
  382. return false; //解锁失败,等待过期自动解锁即可
  383. } catch (Exception e) {
  384. LOGGER.error("releaseDistributedLock->i={},key={}", i, lockKey, e);
  385. TimeUtil.sleep(FAILED_SLEEP);
  386. } finally {
  387. jedis.close();
  388. }
  389. }
  390. throw new Exception("RedisUtil::releaseDistributedLock exception");
  391. }
  392. }