面试题答案
一键面试基本原理
- 唯一性:利用Redis的单线程特性,当多个客户端尝试使用相同的key来获取锁时,只有一个客户端能成功设置这个key,这就保证了锁的唯一性。例如,一个抢购场景中,众多请求同时尝试获取锁,只有第一个成功设置key的请求能进入抢购逻辑。
- 有效期:为获取的锁设置一个合理的过期时间,防止因持有锁的服务崩溃等异常情况导致锁无法释放,出现死锁。比如设置过期时间为10秒,如果10秒内服务处理完业务逻辑,就会主动释放锁;若未处理完,10秒后锁也会自动释放。
核心代码实现步骤
- 引入依赖:在Spring Boot项目的
pom.xml
文件中添加Redis相关依赖,例如:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置Redis:在
application.yml
中配置Redis连接信息,如:
spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
- 编写获取锁方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisLockUtil {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public boolean tryLock(String lockKey, String requestId, int expireTime) {
// 使用setIfAbsent方法尝试设置锁
Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, requestId);
if (result != null && result) {
// 设置锁的过期时间
redisTemplate.expire(lockKey, expireTime, TimeUnit.SECONDS);
return true;
}
return false;
}
}
这里lockKey
是锁的唯一标识,requestId
用于标识请求,防止误删其他请求的锁,expireTime
是锁的过期时间。
4. 编写释放锁方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class RedisLockUtil {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void unlock(String lockKey, String requestId) {
// 先获取锁的值
String value = redisTemplate.opsForValue().get(lockKey);
if (requestId.equals(value)) {
// 如果值与请求标识相同,删除锁
redisTemplate.delete(lockKey);
}
}
}
在业务代码中使用锁时,先调用tryLock
方法获取锁,成功后执行业务逻辑,最后调用unlock
方法释放锁。例如:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExampleController {
@Autowired
private RedisLockUtil redisLockUtil;
@GetMapping("/example")
public String example() {
String lockKey = "example_lock";
String requestId = "123456";
int expireTime = 10;
if (redisLockUtil.tryLock(lockKey, requestId, expireTime)) {
try {
// 执行业务逻辑
return "业务处理成功";
} finally {
redisLockUtil.unlock(lockKey, requestId);
}
} else {
return "获取锁失败";
}
}
}