fix 领红包加锁

This commit is contained in:
wells
2026-08-05 18:18:49 +08:00
parent ecb372119c
commit 7f96115a6a
2 changed files with 65 additions and 21 deletions
@@ -7,6 +7,7 @@ import com.tailbet.model.entity.RedPacketRecv;
import com.tailbet.model.vo.R; import com.tailbet.model.vo.R;
import com.tailbet.model.vo.UserContext; import com.tailbet.model.vo.UserContext;
import com.tailbet.service.IRedPacketService; import com.tailbet.service.IRedPacketService;
import com.tailbet.util.RedisLockUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -42,7 +43,12 @@ public class RedPacketController {
public R<RedPacketRecv> receiveRp(@RequestBody ReceiveRpDTO dto) { public R<RedPacketRecv> receiveRp(@RequestBody ReceiveRpDTO dto) {
try { try {
Long userId = UserContext.getUserId(); Long userId = UserContext.getUserId();
var recv = redPacketService.receiveRp(dto.getRpId(), userId); // 使用分布式锁防止多领
var recv = RedisLockUtil.lock("rp:receive:" + dto.getRpId(),
() -> redPacketService.receiveRp(dto.getRpId(), userId));
if (recv == null) {
return R.fail("领取失败,请重试");
}
return R.ok(recv); return R.ok(recv);
} catch (RuntimeException e) { } catch (RuntimeException e) {
return R.fail(e.getMessage()); return R.fail(e.getMessage());
+58 -20
View File
@@ -3,21 +3,22 @@ package com.tailbet.job;
import com.tailbet.model.entity.GameRound; import com.tailbet.model.entity.GameRound;
import com.tailbet.model.entity.RedPacket; import com.tailbet.model.entity.RedPacket;
import com.tailbet.model.entity.User; import com.tailbet.model.entity.User;
import com.tailbet.mapper.DrawRecordMapper;
import com.tailbet.mapper.DigitWhiteMapper;
import com.tailbet.mapper.GameRoundMapper; import com.tailbet.mapper.GameRoundMapper;
import com.tailbet.mapper.RedPacketMapper; import com.tailbet.mapper.RedPacketMapper;
import com.tailbet.mapper.RedPacketRecvMapper; import com.tailbet.mapper.RedPacketRecvMapper;
import com.tailbet.mapper.UserMapper;
import com.tailbet.mapper.DigitWhiteMapper;
import com.tailbet.mapper.DrawRecordMapper;
import com.tailbet.mapper.SysConfigMapper; import com.tailbet.mapper.SysConfigMapper;
import com.tailbet.mapper.UserMapper;
import com.tailbet.model.entity.DigitWhite; import com.tailbet.model.entity.DigitWhite;
import com.tailbet.model.entity.DrawRecord; import com.tailbet.model.entity.DrawRecord;
import com.tailbet.model.entity.RedPacketRecv; import com.tailbet.model.entity.RedPacketRecv;
import com.tailbet.model.entity.SysConfig; import com.tailbet.model.entity.SysConfig;
import com.tailbet.openim.OpenIMClient;
import com.tailbet.service.IGameService; import com.tailbet.service.IGameService;
import com.tailbet.service.IRedPacketService; import com.tailbet.service.IRedPacketService;
import com.tailbet.service.IFakeUserService; import com.tailbet.service.IFakeUserService;
import com.tailbet.openim.OpenIMClient; import com.tailbet.util.RedisLockUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -161,13 +162,15 @@ public class GameJob {
break; break;
} }
final User fakeUser = fakeToUse;
try { try {
redPacketService.receiveRp(rp.getId(), fakeToUse.getId()); // 使用分布式锁防止多领
RedisLockUtil.lock("rp:receive:" + rp.getId(),
() -> redPacketService.receiveRp(rp.getId(), fakeUser.getId()));
log.info("假人{}领取红包{}剩余份额", fakeToUse.getId(), rp.getId()); log.info("假人{}领取红包{}剩余份额", fakeToUse.getId(), rp.getId());
} catch (Exception e) { } catch (Exception e) {
log.error("假人领取红包失败: rpId={}, fakeId={}, error={}", rp.getId(), fakeToUse.getId(), e.getMessage()); log.error("假人领取红包失败: rpId={}, fakeId={}, error={}", rp.getId(), fakeUser.getId(), e.getMessage());
// 可能是红包已领完,退出循环
break;
} }
} }
} }
@@ -493,18 +496,53 @@ public class GameJob {
private Integer digit; private Integer digit;
private LocalDateTime executeTime; private LocalDateTime executeTime;
public String getTaskId() { return taskId; } public String getTaskId() {
public void setTaskId(String taskId) { this.taskId = taskId; } return taskId;
public String getType() { return type; } }
public void setType(String type) { this.type = type; }
public Long getRoundId() { return roundId; } public void setTaskId(String taskId) {
public void setRoundId(Long roundId) { this.roundId = roundId; } this.taskId = taskId;
public Long getGroupId() { return groupId; } }
public void setGroupId(Long groupId) { this.groupId = groupId; }
public Integer getDigit() { return digit; } public String getType() {
public void setDigit(Integer digit) { this.digit = digit; } return type;
public LocalDateTime getExecuteTime() { return executeTime; } }
public void setExecuteTime(LocalDateTime executeTime) { this.executeTime = executeTime; }
public void setType(String type) {
this.type = type;
}
public Long getRoundId() {
return roundId;
}
public void setRoundId(Long roundId) {
this.roundId = roundId;
}
public Long getGroupId() {
return groupId;
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
public Integer getDigit() {
return digit;
}
public void setDigit(Integer digit) {
this.digit = digit;
}
public LocalDateTime getExecuteTime() {
return executeTime;
}
public void setExecuteTime(LocalDateTime executeTime) {
this.executeTime = executeTime;
}
} }
/** /**