上篇文章提到了我解决bug的时候,尝试引入分布式锁解决问题,操作的时候发现我们的项目简单到没有redis。需要从头开始了。这里就简单记录一下吧
引入两个相关的包:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
这里是一个分布式锁的实现类,可以根据不同的需求调用不同的方法。
package com.guava.mall.app.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class RedisLockHandler {
/**
* 最大持有锁的时间(毫秒)
*/
private final static long LOCK_EXPIRE = 30 * 1000L;
/**
* 尝试获取锁的时间间隔(毫秒)
*/
private final static long LOCK_TRY_INTERVAL = 30L;
/**
* 获取锁最大等待时间( 毫秒 )
*/
private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;
@Resource
private RedisTemplate redisTemplate;
/**
* 尝试获取 分布式锁
*
* @param lockKey 锁名
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey) {
return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_TRY_INTERVAL);
}
/**
* 尝试获取 分布式锁(不自动释放锁)
*
* @param lockKey 锁名
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLockNotAutoRelease(String lockKey) {
return getLock(lockKey, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, -1);
}
/**
* 尝试获取 分布式锁
*
* @param lockKey 锁名
* @param timeout 获取锁最大等待时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey, long timeout) {
return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
}
/**
* 尝试获取 分布式锁(不自动释放锁)
*
* @param lockKey 锁名
* @param timeout 获取锁最大等待时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLockNotAutoRelease(String lockKey, long timeout) {
return getLock(lockKey, timeout, LOCK_TRY_INTERVAL, -1);
}
/**
* 尝试获取 分布式锁
*
* @param lockKey 锁名
* @param timeout 获取锁最大等待时间
* @param tryInterval 获取锁尝试 时间间隔
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey, long timeout, long tryInterval) {
return getLock(lockKey, timeout, tryInterval, LOCK_EXPIRE);
}
/**
* 尝试获取 分布式锁(不释放锁)
*
* @param lockKey 锁名
* @param timeout 获取锁最大等待时间
* @param tryInterval 获取锁尝试 时间间隔
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLockNotAutoRelease(String lockKey, long timeout, long tryInterval) {
return getLock(lockKey, timeout, tryInterval, -1);
}
/**
* 尝试获取 分布式锁
*
* @param lockKey 锁名
* @param timeout 获取锁最大等待时间
* @param tryInterval 获取锁尝试 时间间隔
* @param lockExpireTime 锁最大持有时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean tryLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
return getLock(lockKey, timeout, tryInterval, lockExpireTime);
}
/**
* 获取分布式锁
*
* @param lockKey 锁名
* @param timeout 获取锁最大等待时间
* @param tryInterval 获取锁尝试 时间间隔
* @param lockExpireTime 锁最大持有时间
* @return true 得到了锁 ,false 获取锁失败
*/
public boolean getLock(String lockKey, long timeout, long tryInterval, long lockExpireTime) {
try {
if (StringUtils.isEmpty(lockKey)) {
return false;
}
long startTime = System.currentTimeMillis();
do {
ValueOperations<String, String> ops = redisTemplate.opsForValue();
boolean success = Boolean.TRUE.equals(lockExpireTime > 0 ? ops.setIfAbsent(lockKey, "lockValue", lockExpireTime, TimeUnit.MILLISECONDS) : ops.setIfAbsent(lockKey, "lockValue"));
if (success) {
return true;
}
Thread.sleep(tryInterval);
} while (System.currentTimeMillis() - startTime < timeout);
} catch (InterruptedException e) {
log.error(e.getMessage());
return false;
}
return false;
}
/**
* 释放锁
*
* @param lockKey
*/
public void unLock(String lockKey) {
if (!StringUtils.isEmpty(lockKey)) {
redisTemplate.delete(lockKey);
}
}
}
使用的时候就很简单了,将这个包引入,然后直接调用方法。
boolean lock = redisLockHandler.tryLock(CREATE_WAVE_LOCK_KEY, 0, 0, 10 * 1000L);
简单记录一下,这里本来是先set再expire的,肯定有问题,若是设置时间的时候挂了,岂不是死锁了。