|
@@ -1488,6 +1488,15 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
|
|
|
// 2 另起定时任务 同步缓存余额到redis中
|
|
|
// 3 启动系统时查询公司账户余额(这个时候要保证余额正确)保存到redis缓存中
|
|
|
|
|
|
+ // 预设值异常对象
|
|
|
+ BalanceRollbackError balanceRollbackError = new BalanceRollbackError();
|
|
|
+ balanceRollbackError.setCompanyId(packetParam.getCompanyId());
|
|
|
+ balanceRollbackError.setUserId(user.getUserId());
|
|
|
+ balanceRollbackError.setLogId(log.getLogId());
|
|
|
+ balanceRollbackError.setVideoId(log.getVideoId());
|
|
|
+ balanceRollbackError.setStatus(0);
|
|
|
+ balanceRollbackError.setMoney(amount);
|
|
|
+
|
|
|
if(packetParam.getCompanyId()== null){
|
|
|
logger.error("发送红包参数错误,公司不能为空,异常请求参数{}",packetParam);
|
|
|
return R.error("发送红包失败,请联系管理员");
|
|
@@ -1496,32 +1505,29 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
|
|
|
|
|
|
// 第一次加锁:预扣减余额
|
|
|
RLock lock1 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + packetParam.getCompanyId());
|
|
|
+ boolean lockAcquired = false;
|
|
|
try {
|
|
|
if (lock1.tryLock(3, 10, TimeUnit.SECONDS)) {
|
|
|
- try {
|
|
|
- BigDecimal originalMoney;
|
|
|
- // 获取当前余额
|
|
|
- String moneyStr = redisCache.getCacheObject(companyMoneyKey);
|
|
|
- if (StringUtils.isNotEmpty(moneyStr)) {
|
|
|
- originalMoney = new BigDecimal(moneyStr);
|
|
|
- }else {
|
|
|
- // 缓存没有值,重启系统恢复redis数据 保证数据正确性
|
|
|
- logger.error("发送红包获取redis余额缓存异常,异常请求参数{}",packetParam);
|
|
|
- return R.error("系统异常,请稍后重试");
|
|
|
- }
|
|
|
-
|
|
|
- if (originalMoney.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
- logger.error("服务商余额不足,异常请求参数{}",packetParam);
|
|
|
- return R.error("服务商余额不足,请联系群主服务器充值!");
|
|
|
- }
|
|
|
-
|
|
|
- // 预扣减金额
|
|
|
- BigDecimal newMoney = originalMoney.subtract(amount);
|
|
|
- redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
|
|
|
-
|
|
|
- } finally {
|
|
|
- lock1.unlock();
|
|
|
+ lockAcquired = true;
|
|
|
+ BigDecimal originalMoney;
|
|
|
+ // 获取当前余额
|
|
|
+ String moneyStr = redisCache.getCacheObject(companyMoneyKey);
|
|
|
+ if (StringUtils.isNotEmpty(moneyStr)) {
|
|
|
+ originalMoney = new BigDecimal(moneyStr);
|
|
|
+ }else {
|
|
|
+ // 缓存没有值,重启系统恢复redis数据 保证数据正确性
|
|
|
+ logger.error("发送红包获取redis余额缓存异常,异常请求参数{}",packetParam);
|
|
|
+ return R.error("系统异常,请稍后重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (originalMoney.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
+ logger.error("服务商余额不足,异常请求参数{}",packetParam);
|
|
|
+ return R.error("服务商余额不足,请联系群主服务器充值!");
|
|
|
}
|
|
|
+
|
|
|
+ // 预扣减金额
|
|
|
+ BigDecimal newMoney = originalMoney.subtract(amount);
|
|
|
+ redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
|
|
|
} else {
|
|
|
logger.error("获取redis锁失败,异常请求参数{}",packetParam);
|
|
|
return R.error("系统繁忙,请稍后重试");
|
|
@@ -1529,17 +1535,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
|
|
|
} catch (Exception e) {
|
|
|
logger.error("预扣减余额失败: 异常请求参数{},异常信息{}", packetParam, e.getMessage(), e);
|
|
|
return R.error("系统异常,请稍后重试");
|
|
|
+ }finally {
|
|
|
+ // 只有在成功获取锁的情况下才释放锁
|
|
|
+ if (lockAcquired && lock1.isHeldByCurrentThread()) {
|
|
|
+ try {
|
|
|
+ lock1.unlock();
|
|
|
+ } catch (IllegalMonitorStateException e) {
|
|
|
+ logger.warn("尝试释放非当前线程持有的锁: companyId={}", packetParam.getCompanyId());
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 预设值异常对象
|
|
|
- BalanceRollbackError balanceRollbackError = new BalanceRollbackError();
|
|
|
- balanceRollbackError.setCompanyId(packetParam.getCompanyId());
|
|
|
- balanceRollbackError.setUserId(user.getUserId());
|
|
|
- balanceRollbackError.setLogId(log.getLogId());
|
|
|
- balanceRollbackError.setVideoId(log.getVideoId());
|
|
|
- balanceRollbackError.setStatus(0);
|
|
|
- balanceRollbackError.setMoney(amount);
|
|
|
-
|
|
|
// 调用第三方接口(锁外操作)
|
|
|
R sendRedPacket;
|
|
|
try {
|
|
@@ -1629,24 +1635,23 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
|
|
|
private void rollbackBalance(BalanceRollbackError balanceRollbackError) {
|
|
|
String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + balanceRollbackError.getCompanyId();
|
|
|
RLock lock2 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + balanceRollbackError.getCompanyId());
|
|
|
-
|
|
|
+ boolean lockAcquired = false;
|
|
|
+ boolean backError=true;
|
|
|
try {
|
|
|
if (lock2.tryLock(3, 10, TimeUnit.SECONDS)) {
|
|
|
- try {
|
|
|
- // 获取当前余额
|
|
|
- String currentMoneyStr = redisCache.getCacheObject(companyMoneyKey);
|
|
|
- if (StringUtils.isEmpty(currentMoneyStr)) {
|
|
|
- throw new RuntimeException("回滚余额异常");
|
|
|
- }
|
|
|
+ lockAcquired=true;
|
|
|
+ // 获取当前余额
|
|
|
+ String currentMoneyStr = redisCache.getCacheObject(companyMoneyKey);
|
|
|
+ if (StringUtils.isEmpty(currentMoneyStr)) {
|
|
|
+ throw new RuntimeException("回滚余额异常");
|
|
|
+ }
|
|
|
|
|
|
- // 回滚金额(加回之前扣减的金额)
|
|
|
- BigDecimal rollbackMoney = new BigDecimal(currentMoneyStr).add(balanceRollbackError.getMoney());
|
|
|
- redisCache.setCacheObject(companyMoneyKey, rollbackMoney.toString());
|
|
|
+ // 回滚金额(加回之前扣减的金额)
|
|
|
+ BigDecimal rollbackMoney = new BigDecimal(currentMoneyStr).add(balanceRollbackError.getMoney());
|
|
|
+ redisCache.setCacheObject(companyMoneyKey, rollbackMoney.toString());
|
|
|
+ backError=false;
|
|
|
+ logger.info("余额回滚成功: companyId={}, amount={}", balanceRollbackError.getCompanyId(), balanceRollbackError.getMoney());
|
|
|
|
|
|
- logger.info("余额回滚成功: companyId={}, amount={}", balanceRollbackError.getCompanyId(), balanceRollbackError.getMoney());
|
|
|
- } finally {
|
|
|
- lock2.unlock();
|
|
|
- }
|
|
|
} else {
|
|
|
logger.warn("回滚余额时获取锁失败: companyId={}", balanceRollbackError.getCompanyId());
|
|
|
// 登记回滚余额异常表
|
|
@@ -1655,8 +1660,18 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
|
|
|
} catch (Exception e) {
|
|
|
logger.error("回滚余额时发生异常: companyId={}", balanceRollbackError.getCompanyId(), e);
|
|
|
// 登记回滚余额异常表
|
|
|
- balanceRollbackErrorMapper.insert(balanceRollbackError);
|
|
|
-
|
|
|
+ if(backError){
|
|
|
+ balanceRollbackErrorMapper.insert(balanceRollbackError);
|
|
|
+ }
|
|
|
+ }finally {
|
|
|
+ // 只有在成功获取锁的情况下才释放锁
|
|
|
+ if (lockAcquired && lock2.isHeldByCurrentThread()) {
|
|
|
+ try {
|
|
|
+ lock2.unlock();
|
|
|
+ } catch (IllegalMonitorStateException e) {
|
|
|
+ logger.warn("尝试释放非当前线程持有的锁: balanceRollbackError={}",balanceRollbackError);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|