どのようにSpringBootを通じて商店街の秒殺システムを実現しますか?
7687 ワード
この文章は主にSpringBootを通じて商店街の秒殺システムを実現する方法を紹介しています。ここでは例示的なコードで紹介されています。
学習自:住所
1.主な流れ
1.1データベース:
1.2環境
window下:Zookeeper、Redis、rabbitmq-server。jdk 1.8以上です。
1.3紹介
ここでは秒殺の機能だけをしています。他の機能は触れません。プロジェクトの運行後、秒殺商品ページにアクセスできます。
ユーザーがログインしていない場合は、詳細をクリックしてログインページにジャンプします。
ユーザーがログインしたら商品の詳細を確認して買い占めができます。
注意してください。ユーザーは一つの商品に対して一回だけ買います。二回目の買い占めをする時は拒絶されます。ユーザーが買い占めに成功したら、非同期でユーザーにメールを送ります。
主なロジックは以上です。コードを見ます
1.4プロジェクト構造、apiパッケージにはいくつかのエニュメレーションとリターン値があり、モデルは主に実体類とsqlマッピングファイルであり、serviceは業務ロジックコードを実現する。
1.5秒殺商品をページやユーザーの操作に使うか、それともMVCモードかを表示します。高さを実現し、秒殺を狙う。
詳しく述べるには、ものが多すぎて、もっと深く知りたいなら、上のリンクをクリックしてください。
基本的な秒殺のロジックは以下の通りです。ユーザーはすでにこの商品を買ったかどうかを判断します。ない場合は秒殺商品の詳細を調べて、商品を秒殺しないでください。在庫が十分かどうかを判断します。
条件に該当すれば、この商品の在庫は1を減らし、その後、再度控除が成功したかどうかを判断し、減額すれば秒殺成功の注文を生成し、同時にユーザーに秒殺成功の情報を通知する。
学習自:住所
1.主な流れ
1.1データベース:
1.2環境
window下:Zookeeper、Redis、rabbitmq-server。jdk 1.8以上です。
1.3紹介
ここでは秒殺の機能だけをしています。他の機能は触れません。プロジェクトの運行後、秒殺商品ページにアクセスできます。
ユーザーがログインしていない場合は、詳細をクリックしてログインページにジャンプします。
ユーザーがログインしたら商品の詳細を確認して買い占めができます。
注意してください。ユーザーは一つの商品に対して一回だけ買います。二回目の買い占めをする時は拒絶されます。ユーザーが買い占めに成功したら、非同期でユーザーにメールを送ります。
主なロジックは以上です。コードを見ます
1.4プロジェクト構造、apiパッケージにはいくつかのエニュメレーションとリターン値があり、モデルは主に実体類とsqlマッピングファイルであり、serviceは業務ロジックコードを実現する。
1.5秒殺商品をページやユーザーの操作に使うか、それともMVCモードかを表示します。高さを実現し、秒殺を狙う。
詳しく述べるには、ものが多すぎて、もっと深く知りたいなら、上のリンクをクリックしてください。
基本的な秒殺のロジックは以下の通りです。ユーザーはすでにこの商品を買ったかどうかを判断します。ない場合は秒殺商品の詳細を調べて、商品を秒殺しないでください。在庫が十分かどうかを判断します。
条件に該当すれば、この商品の在庫は1を減らし、その後、再度控除が成功したかどうかを判断し、減額すれば秒殺成功の注文を生成し、同時にユーザーに秒殺成功の情報を通知する。
public Boolean killItem(Integer killId, Integer userId) throws Exception {
Boolean result=false;
//TODO:
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
//TODO:
ItemKill itemKill=itemKillMapper.selectById(killId);
//TODO: canKill=1?
if (itemKill!=null && 1==itemKill.getCanKill() ){
//TODO: -
int res=itemKillMapper.updateKillItem(killId);
//TODO: ? - ,
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception(" !");
}
return result;
}
コード最適化1:redisの分散式錠を使って、現在の秒殺商品のidと現在のユーザーのidを使ってkeyを構成して、SteringBufferを使ってつなぎ合わせて、雪花アルゴリズムを使ってvalueを生成して、redisに保存します。
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* -redis
* @param killId
* @param userId
* @return
* @throws Exception
*/
@Override
public Boolean killItemV3(Integer killId, Integer userId) throws Exception {
Boolean result=false;
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
//TODO: Redis - -
ValueOperations valueOperations=stringRedisTemplate.opsForValue();
final String key=new StringBuffer().append(killId).append(userId).append("-RedisLock").toString();
final String value=RandomUtil.generateOrderCode();
Boolean cacheRes=valueOperations.setIfAbsent(key,value); //luna “ ”,
//TOOD:redis
if (cacheRes){
stringRedisTemplate.expire(key,30, TimeUnit.SECONDS);
try {
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}catch (Exception e){
throw new Exception(" 、 !");
}finally {
if (value.equals(valueOperations.get(key).toString())){
stringRedisTemplate.delete(key);
}
}
}
}else{
throw new Exception("Redis- !");
}
return result;
}
コード最適化2:Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS);30秒ごとに現在のユーザがタイムアウトしたかどうかを判断します。一回のカートンによってプログラム全体に影響がありません。
@Autowired
private RedissonClient redissonClient;
/**
* -redisson
* @param killId
* @param userId
* @return
* @throws Exception
*/
@Override
public Boolean killItemV4(Integer killId, Integer userId) throws Exception {
Boolean result=false;
final String lockKey=new StringBuffer().append(killId).append(userId).append("-RedissonLock").toString();
RLock lock=redissonClient.getLock(lockKey);
try {
Boolean cacheRes=lock.tryLock(30,10,TimeUnit.SECONDS);
if (cacheRes){
//TODO:
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception("redisson- !");
}
}
}finally {
lock.unlock();
//lock.forceUnlock();
}
return result;
}
コード最適化3:
@Autowired
private CuratorFramework curatorFramework;
private static final String pathPrefix="/kill/zkLock/";
/**
* - ZooKeeper
* @param killId
* @param userId
* @return
* @throws Exception
*/
@Override
public Boolean killItemV5(Integer killId, Integer userId) throws Exception {
Boolean result=false;
InterProcessMutex mutex=new InterProcessMutex(curatorFramework,pathPrefix+killId+userId+"-lock");
try {
if (mutex.acquire(10L,TimeUnit.SECONDS)){
//TODO:
if (itemKillSuccessMapper.countByKillUserId(killId,userId) <= 0){
ItemKill itemKill=itemKillMapper.selectByIdV2(killId);
if (itemKill!=null && 1==itemKill.getCanKill() && itemKill.getTotal()>0){
int res=itemKillMapper.updateKillItemV2(killId);
if (res>0){
commonRecordKillSuccessInfo(itemKill,userId);
result=true;
}
}
}else{
throw new Exception("zookeeper- !");
}
}
}catch (Exception e){
throw new Exception(" 、 !");
}finally {
if (mutex!=null){
mutex.release();
}
}
return result;
}
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。