RedisLock.java 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package com.izouma.nineth.service;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.data.redis.core.StringRedisTemplate;
  6. import org.springframework.stereotype.Component;
  7. @Component
  8. @Slf4j
  9. public class RedisLock {
  10. @Autowired
  11. private StringRedisTemplate stringRedisTemplate;
  12. /**
  13. * 加锁
  14. *
  15. * @param key productId - 商品的唯一标志
  16. * @param value 当前时间+超时时间 也就是时间戳
  17. * @return
  18. */
  19. public boolean lock(String key, String value) {
  20. if (stringRedisTemplate.opsForValue().setIfAbsent(key, value)) {//对应setnx命令
  21. //可以成功设置,也就是key不存在
  22. return true;
  23. }
  24. //判断锁超时 - 防止原来的操作异常,没有运行解锁操作 防止死锁
  25. String currentValue = stringRedisTemplate.opsForValue().get(key);
  26. //如果锁过期
  27. if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {//currentValue不为空且小于当前时间
  28. //获取上一个锁的时间value
  29. String oldValue = stringRedisTemplate.opsForValue().getAndSet(key, value);//对应getset,如果key存在
  30. //假设两个线程同时进来这里,因为key被占用了,而且锁过期了。获取的值currentValue=A(get取的旧的值肯定是一样的),两个线程的value都是B,key都是K.锁时间已经过期了。
  31. //而这里面的getAndSet一次只会一个执行,也就是一个执行之后,上一个的value已经变成了B。只有一个线程获取的上一个值会是A,另一个线程拿到的值是B。
  32. if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
  33. //oldValue不为空且oldValue等于currentValue,也就是校验是不是上个对应的商品时间戳,也是防止并发
  34. return true;
  35. }
  36. }
  37. return false;
  38. }
  39. /**
  40. * 解锁
  41. *
  42. * @param key
  43. * @param value
  44. */
  45. public void unlock(String key, String value) {
  46. try {
  47. String currentValue = stringRedisTemplate.opsForValue().get(key);
  48. if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
  49. stringRedisTemplate.opsForValue().getOperations().delete(key);//删除key
  50. }
  51. } catch (Exception e) {
  52. log.error("[Redis分布式锁] 解锁出现异常了,{}", e);
  53. }
  54. }
  55. }