springboot集成redis實現(xiàn)簡單秒殺系統(tǒng)
本文實例為大家分享了springboot集成redis實現(xiàn)簡單秒殺系統(tǒng)的具體代碼,供大家參考,具體內(nèi)容如下
1. 直接service,我們會介紹兩種秒殺模式
public interface GoodsService {
/**
* 通過lua腳本實現(xiàn)的秒殺
* @param skuCode 商品編碼
* @param buyNum 購買數(shù)量
* @return 購買數(shù)量
*/
Long flashSellByLuaScript(String skuCode,int buyNum);
/**
* 通過redis 事務(wù) 實現(xiàn)的秒殺
* @param skuCode 商品編碼
* @param buyNum 購買數(shù)量
* @return 購買數(shù)量
*/
Long flashSellByRedisWatch(String skuCode,int buyNum);
}
2. service實現(xiàn)類
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
@Service
public class GoodsServiceImpl implements GoodsService {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public Long flashSellByLuaScript(String skuCode,int num) {
//下面是lua腳本
String luaScript ="local buyNum = ARGV[1]\n" +
"local goodsKey = KEYS[1] \n" +
"local goodsNum = redis.call('get',goodsKey) \n" +
"if goodsNum >= buyNum \n" +
"then redis.call('decrby',goodsKey,buyNum) \n" +
"return buyNum \n" +
"else \n" +
"return '0'\n" +
"end\n" +
"\n" ;
DefaultRedisScript<String> re = new DefaultRedisScript<String>();
//設(shè)置腳本
re.setScriptText(luaScript);
//定義返回值類型,注意,如果沒有這個定義,Spring不會返回結(jié)果
re.setResultType(String.class);
RedisSerializer<String> stringRedisSerializer = stringRedisTemplate.getStringSerializer();
//執(zhí)行LUA腳本
String result = (String) stringRedisTemplate.execute(re, stringRedisSerializer, stringRedisSerializer, null);
return Long.valueOf(result);
}
@Override
public Long flashSellByRedisWatch(String skuCode,int num){
SessionCallback<Long> sessionCallback = new SessionCallback<Long>() {
@Override
public Long execute(RedisOperations operations) throws DataAccessException {
int result = num;
//redis 樂觀鎖
//我們觀察商品編碼是否發(fā)生改變
operations.watch(skuCode);
ValueOperations<String, String> valueOperations = operations.opsForValue();
String goodsNumStr = valueOperations.get(skuCode);
Integer goodsNum = Integer.valueOf(goodsNumStr);
//標(biāo)記一個事務(wù)塊的開始。
//事務(wù)塊內(nèi)的多條命令會按照先后順序被放進一個隊列當(dāng)中,
//最后由 EXEC 命令原子性(atomic)地執(zhí)行。
operations.multi();
if (goodsNum >= num) {
valueOperations.increment(skuCode, 0 - num);
} else {
result = 0;
}
//多條命令執(zhí)行的結(jié)果集合
List exec = operations.exec();
if(exec.size()>0){
System.out.println(exec);
}
return (long) result;
}
};
return stringRedisTemplate.execute(sessionCallback);
}
//省略 其他的方法
}
3. controller
但是首先要向你的redis里面仍一個數(shù)據(jù),key='xiaomi',value='100'
@ApiOperation(value = "用事務(wù)秒殺測試接口", notes = "用事務(wù)秒殺測試接口")
@RequestMapping(value = "/miaoTransaction", method = RequestMethod.GET)
@ResponseBody
public Long miaoTransaction() {
Long res = goodsService.flashSellByRedisWatch("xiaomi", 1);
return res;
}
@ApiOperation(value = " 秒殺Lua測試接口", notes = "秒殺Lua測試接口")
@RequestMapping(value = "/miaoLua", method = RequestMethod.GET)
@ResponseBody
public Long miaoLua() {
Long res = goodsService.flashSellByRedisWatch("xiaomi", 1);
System.out.println(res.toString());
return res;
}
然后就可以用jemeter并發(fā)訪問了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Cloud Stream微服務(wù)消息框架原理及實例解析
這篇文章主要介紹了Spring Cloud Stream微服務(wù)消息框架原理及實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
Spring-cloud Config Server的3種配置方式
這篇文章主要介紹了Spring-cloud Config Server的3種配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Java使用ThreadLocal實現(xiàn)當(dāng)前登錄信息的存取功能
ThreadLocal和其他并發(fā)工具一樣,也是用于解決多線程并發(fā)訪問,下這篇文章主要給大家介紹了關(guān)于Java使用ThreadLocal實現(xiàn)當(dāng)前登錄信息的存取功能,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02
使用Idea或Datagrip導(dǎo)入excel數(shù)據(jù)的方法
這篇文章主要介紹了使用Idea或Datagrip導(dǎo)入excel數(shù)據(jù)的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11
java中線程池最實用的創(chuàng)建與關(guān)閉指南
試中經(jīng)常會問到,創(chuàng)建一個線程池需要哪些參數(shù)啊,線程池的工作原理啊,卻很少會問到線程池如何安全關(guān)閉的,下面這篇文章主要給大家介紹了關(guān)于java中線程池最實用的創(chuàng)建與關(guān)閉的相關(guān)資料,需要的朋友可以參考下2021-09-09

