秒杀在电商业务中是非常典型的需求,有各种方案,下面浅析一下使用redis如何来实现。
场景:有个秒杀系统,大家都来抢100瓶飞天茅台,先到先得。
示例:通过springboot整合redis,利用StringRedisTemplate操作redis的list队列尝试一下。
@Component
public class RedisService {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 添加字符串并设置过期时间
* @param key
* @param value
* @param duration
*/
public void addString(String key, String value, Duration duration) {
stringRedisTemplate.opsForValue().set(key, value, duration);
}
/**
* 查找字符串
* @param key
* @return
*/
public String findString(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
/**
* 根据Key删除
* @param key
* @return
*/
public Boolean deleteByKey(String key) {
return stringRedisTemplate.delete(key);
}
/**
* 在队列尾部减少一个对象
* @param listName
* @return
*/
public String removeOneEntryOnListRight(String listName) {
return stringRedisTemplate.opsForList().rightPop(listName);
}
/**
* 在队列头部新增对象
* @param listName
* @param args
* @return
*/
public Long addEntriesOnListLeft(String listName, Collection<String> args) {
return stringRedisTemplate.opsForList().leftPushAll(listName, args);
}
}
其中主要是addEntriesOnListLeft和removeOneEntryOnListRight方法。addEntriesOnListLeft方法在队列的头部新增对象,若没有这个队列则会创建该队列,然后将一个集合统统塞到这个队列中。removeOneEntryOnListRight方法会删除队列中最后一个元素,然后返回这个元素的值,若队列中灭有元素了,那么会返回null,且它们都是原子操作。
这样,每个请求都无需经过加锁操作,直接利用redis的单线程特性,即可实现高并发下的秒杀:请求到达redis,redis会逐个执行,每一次执行要么返回一个值,要么返回null,很显然,有返回值的就是抢到了,返回null的就是没抢到。
对应到redis的操作指令为在队列的左侧新增lpush和在队列的右侧消费rpop。
使用方式
先在任务开始时向redis队列中插入一个大队列
List<String> entriesList = new LinkedList<>();
for (int i = 0; i < 100; i++){
entriesList.add("商品" + i);
}
redisService.addEntriesOnListLeft("listName",entriesList);
后在秒杀的方法中操作如下
String redisResult = redisService.removeOneEntryOnListRight("listName");
if (null == redisResult) {
//说明没抢到
System.out.println("没抢到");
}else{
//说明抢到了 执行抢到逻辑
System.out.println("抢到了");
}
感兴趣的小伙伴可以尝试一下,看看是否满足秒杀场景哦( ̄▽ ̄)"