瀏覽代碼

公司余额减扣

xgb 1 天之前
父節點
當前提交
488d7a8719

+ 2 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java

@@ -203,4 +203,6 @@ public interface CompanyMapper
      * 查询企微主体管理公司列表
      */
     List<OptionsVO> getCompanyListByCorpId(@Param("corpId") String corpId);
+
+    List<Company> selectCompanyMoneyAllList();
 }

+ 25 - 19
fs-service/src/main/java/com/fs/course/service/impl/BalanceRollbackErrorServiceImpl.java

@@ -90,7 +90,10 @@ public class BalanceRollbackErrorServiceImpl extends ServiceImpl<BalanceRollback
     public void initCompanyBalance() {
 
         // 查询公司表 Company
-        List<Company> companyList = companyMapper.selectCompanyAllList();
+        List<Company> companyList = companyMapper.selectCompanyMoneyAllList();
+        if (companyList.isEmpty()) {
+            return;
+        }
         for (Company company : companyList) {
             String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + company.getCompanyId();
             // 判断缓存为空初始化
@@ -114,28 +117,25 @@ public class BalanceRollbackErrorServiceImpl extends ServiceImpl<BalanceRollback
 
         // 加锁:扣减余额
         RLock lock1 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + companyId);
+        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 {
-                        logger.error("获取公司余额缓存异常公司id{},",companyId);
-                        logger.error("获取公司余额缓存异常数据{},",errorList);
-                        throw new RuntimeException("获取公司余额缓存异常");
-                    }
-
-                    // 扣减金额
-                    BigDecimal newMoney = originalMoney.subtract(totalAmount);
-                    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 {
+                    logger.error("获取公司余额缓存异常公司id{},",companyId);
+                    logger.error("获取公司余额缓存异常数据{},",errorList);
+                    throw new RuntimeException("获取公司余额缓存异常");
                 }
 
+                // 扣减金额
+                BigDecimal newMoney = originalMoney.subtract(totalAmount);
+                redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
+
                 // 批量更新余额异常数据 状态改为1
                 for (BalanceRollbackError error : errorList) {
                     error.setStatus(1);
@@ -156,6 +156,12 @@ public class BalanceRollbackErrorServiceImpl extends ServiceImpl<BalanceRollback
             logger.error("InterruptedException异常公司id{},",companyId);
             logger.error("InterruptedException异常数据{},",errorList);
             throw new RuntimeException(e);
+        }if (lockAcquired && lock1.isHeldByCurrentThread()) {
+            try {
+                lock1.unlock();
+            } catch (IllegalMonitorStateException e) {
+                logger.warn("尝试释放非当前线程持有的锁: balanceRollbackError={}",errorList);
+            }
         }
 
     }

+ 63 - 48
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -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);
+                }
+            }
         }
     }
 

+ 4 - 0
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -262,4 +262,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         inner join qw_company qc on find_in_set(c.company_id, qc.company_ids)
         where c.is_del= 0 and qc.corp_id = #{corpId}
     </select>
+
+    <select id="selectCompanyMoneyAllList" resultType="com.fs.company.domain.Company">
+        select company_id,company_name,money from company where is_del= 0
+    </select>
 </mapper>