Commit ef434138 authored by tangtuo's avatar tangtuo

解决同一个用户可以并发领取纪念版nft的问题

parent 94363fad
......@@ -29,7 +29,7 @@ public class RedisConstant {
/**
* 纪念版nft领取成员列表
*/
public static final String COMMEMORATE_NFT_MEMBERS_PREFIX = "commemorateNft:members";
public static final String COMMEMORATE_NFT_MEMBERS_PREFIX = "commemorateNft:members:";
......
......@@ -22,6 +22,7 @@ import com.fzm.common.utils.JsonUtil;
import com.fzm.common.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
......@@ -103,56 +104,68 @@ public class CommemorateNftServiceImpl extends ServiceImpl<CommemorateNftMapper,
@Override
public Boolean receive(Integer id) {
CommemorateNft commemorateNft = getById(id);
if (commemorateNft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此纪念版nft详情,请稍后再试");
}
User user = userService.getUserByToken();
// 先判断当前用户有没有领取过此纪念版nft
if (redisUtil.sIsMember(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, user.getId().toString())) {
throw GlobalException.newException(ResultCode.FAILED, "此纪念版nft每个用户只能领取一次");
}
// 获取此纪念版nft发行数的信号量
RSemaphore semaphore = redisson.getSemaphore(RedisConstant.COMMEMORATE_NFT_PREFIX + id);
// 判断纪念版nft有没有被领取完
boolean acquire = semaphore.tryAcquire();
// 领取完毕
if (!acquire) {
throw GlobalException.newException(ResultCode.FAILED, "抱歉,此纪念版nft已全部被领取完");
// 加锁,避免一个用户可以并发领取
RLock lock = redisson.getLock("receive:nft:" + user.getId());
boolean tryLock = lock.tryLock();
if (!tryLock){
throw GlobalException.newException(ResultCode.RECEIVE_ERROR, "操作频繁");
}
// 领取纪念版nft
String hash = paraChainClient.evmTransferNFT1155(contractName, commemorateNft.getPublishAddress(), null, user.getWallet(), commemorateNft.getTokenId(), 1, true);
if (StringUtils.isBlank(hash)) {
// 领取失败要释放信号量
semaphore.release();
throw GlobalException.newException(ResultCode.FAILED, "nft领取失败");
}
// 确认转让结果
TxResult txResult = paraChainClient.cycleConfirmTxWithHash(hash, true, 1000);
if (!TxStatusEnum.SUCCESS.equals(txResult.getStatus())) {
// 领取失败要释放信号量
semaphore.release();
throw GlobalException.newException(ResultCode.RECEIVE_ERROR, txResult.getErrMsg().getValue());
try {
CommemorateNft commemorateNft = getById(id);
if (commemorateNft == null) {
throw GlobalException.newException(ResultCode.DATA_ERROR, "没找到此纪念版nft详情,请稍后再试");
}
// 先判断当前用户有没有领取过此纪念版nft
if (redisUtil.sIsMember(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, user.getId().toString())) {
throw GlobalException.newException(ResultCode.FAILED, "此纪念版nft每个用户只能领取一次");
}
// 获取此纪念版nft发行数的信号量
RSemaphore semaphore = redisson.getSemaphore(RedisConstant.COMMEMORATE_NFT_PREFIX + id);
// 判断纪念版nft有没有被领取完
boolean acquire = semaphore.tryAcquire();
// 领取完毕
if (!acquire) {
throw GlobalException.newException(ResultCode.FAILED, "抱歉,此纪念版nft已全部被领取完");
}
// 领取纪念版nft
String hash = paraChainClient.evmTransferNFT1155(contractName, commemorateNft.getPublishAddress(), null, user.getWallet(), commemorateNft.getTokenId(), 1, true);
if (StringUtils.isBlank(hash)) {
// 领取失败要释放信号量
semaphore.release();
throw GlobalException.newException(ResultCode.FAILED, "nft领取失败");
}
// 确认转让结果
TxResult txResult = paraChainClient.cycleConfirmTxWithHash(hash, true, 1000);
if (!TxStatusEnum.SUCCESS.equals(txResult.getStatus())) {
// 领取失败要释放信号量
semaphore.release();
throw GlobalException.newException(ResultCode.RECEIVE_ERROR, txResult.getErrMsg().getValue());
}
String realHash = paraChainClient.getRealTxHashFromGrp(hash);
Nft nft = new Nft();
BeanUtil.copyProperties(commemorateNft, nft, true);
// 获取当前用户领取nft的领取顺序编号
int availablePermits = commemorateNft.getCount() - semaphore.availablePermits();
// nft编号为BJIFF11+5为顺序编号 : BJIFF1100123
String code = "00000" + availablePermits;
nft.setNftId("BJIFF11" + code.substring(code.length() - 5));
nft.setTransferHash(realHash);
nft.setUserId(user.getId());
nft.setCreateDate(new Date());
nft.setUpdateDate(new Date());
nft.setIsArchives(SystemConstant.BOOLEAN_DATA_TRUE);
nft.setIsGrant(SystemConstant.BOOLEAN_DATA_FALSE);
nft.setIsCommemorate(SystemConstant.BOOLEAN_DATA_TRUE);
nftService.save(nft);
// 领取完毕,把当前用户id加入到纪念版nft的领取记录中
redisUtil.sAdd(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, user.getId().toString());
return true;
} finally {
lock.unlock();
}
String realHash = paraChainClient.getRealTxHashFromGrp(hash);
Nft nft = new Nft();
BeanUtil.copyProperties(commemorateNft, nft, true);
// 获取当前用户领取nft的领取顺序编号
int availablePermits = commemorateNft.getCount() - semaphore.availablePermits();
// nft编号为BJIFF11+5为顺序编号 : BJIFF1100123
String code = "00000" + availablePermits;
nft.setNftId("BJIFF11" + code.substring(code.length() - 5));
nft.setTransferHash(realHash);
nft.setUserId(user.getId());
nft.setCreateDate(new Date());
nft.setUpdateDate(new Date());
nft.setIsArchives(SystemConstant.BOOLEAN_DATA_TRUE);
nft.setIsGrant(SystemConstant.BOOLEAN_DATA_FALSE);
nft.setIsCommemorate(SystemConstant.BOOLEAN_DATA_TRUE);
nftService.save(nft);
// 领取完毕,把当前用户id加入到纪念版nft的领取记录中
redisUtil.sAdd(RedisConstant.COMMEMORATE_NFT_MEMBERS_PREFIX + id, user.getId().toString());
return true;
}
public static void main(String[] args) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment