Commit f0a8beadad012f499e279e58980893aef7f31b5e

Authored by wangqian
1 parent 487e54c6

增加单位积分查询功能

1、上报积分增加
2、退回积分扣减
3、查询列表增加当前派单任务积分字段
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/redis/IntegralLockCoreRedisDAO.java 0 → 100644
  1 +package com.zteits.urbanops.module.garden.dal.redis;
  2 +
  3 +import jakarta.annotation.Resource;
  4 +import lombok.extern.slf4j.Slf4j;
  5 +import org.redisson.api.RLock;
  6 +import org.redisson.api.RedissonClient;
  7 +import org.springframework.stereotype.Component;
  8 +import org.springframework.util.Assert;
  9 +
  10 +import java.util.concurrent.TimeUnit;
  11 +
  12 +/**
  13 + * 积分操作分布式锁通用工具类
  14 + */
  15 +@Slf4j
  16 +@Component
  17 +public class IntegralLockCoreRedisDAO {
  18 +
  19 + // 积分操作锁前缀
  20 + private static final String INTEGRAL_LOCK_PREFIX = "integral:operate:%s:%s";
  21 + // 锁持有超时时间(30秒)
  22 + public static final long INTEGRAL_LOCK_TIMEOUT_MILLIS = 30 * 1000L;
  23 +
  24 + @Resource
  25 + private RedissonClient redissonClient;
  26 +
  27 + /**
  28 + * 加锁执行积分操作逻辑
  29 + * @param unitId 单位ID
  30 + * @param statDate 统计日期
  31 + * @param timeoutMillis 锁持有超时时间
  32 + * @param runnable 要执行的核心业务逻辑
  33 + */
  34 + public void lock(String unitId, String statDate, Long timeoutMillis, Runnable runnable) {
  35 + // 空值校验
  36 + Assert.hasText(unitId, "单位ID不能为空");
  37 + Assert.hasText(statDate, "统计日期不能为空");
  38 + Assert.notNull(timeoutMillis, "锁超时时间不能为空");
  39 + Assert.notNull(runnable, "执行逻辑不能为空");
  40 +
  41 + // 构建细粒度锁Key
  42 + String lockKey = String.format(INTEGRAL_LOCK_PREFIX, unitId, statDate);
  43 + RLock lock = redissonClient.getLock(lockKey);
  44 + boolean lockAcquired = false;
  45 +
  46 + try {
  47 + // 非阻塞获取锁:3秒等待超时,timeoutMillis自动过期
  48 + lockAcquired = lock.tryLock(3, timeoutMillis, TimeUnit.MILLISECONDS);
  49 + if (!lockAcquired) {
  50 + String errorMsg = String.format("获取积分操作锁失败,单位ID:%s,统计日期:%s", unitId, statDate);
  51 + log.error(errorMsg);
  52 + throw new RuntimeException(errorMsg);
  53 + }
  54 + log.info("成功获取积分操作锁,锁Key:{}", lockKey);
  55 +
  56 + // 执行核心业务逻辑
  57 + runnable.run();
  58 +
  59 + } catch (InterruptedException e) {
  60 + log.error("获取积分操作锁被中断,单位ID:{},统计日期:{}", unitId, statDate, e);
  61 + Thread.currentThread().interrupt();
  62 + throw new RuntimeException("积分操作锁获取被中断,请重试", e);
  63 + } finally {
  64 + // 安全释放锁
  65 + if (lockAcquired && lock.isHeldByCurrentThread()) {
  66 + try {
  67 + lock.unlock();
  68 + log.info("成功释放积分操作锁,锁Key:{}", lockKey);
  69 + } catch (Exception e) {
  70 + log.error("释放积分操作锁异常,锁Key:{}", lockKey, e);
  71 + }
  72 + }
  73 + }
  74 + }
  75 +}
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/unitintegraltotal/UnitIntegralServiceImpl.java
1 package com.zteits.urbanops.module.garden.service.unitintegraltotal; 1 package com.zteits.urbanops.module.garden.service.unitintegraltotal;
2 2
  3 +import cn.hutool.extra.spring.SpringUtil;
3 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 4 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 import com.baomidou.mybatisplus.core.toolkit.Wrappers; 5 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
5 import com.zteits.urbanops.framework.common.util.object.BeanUtils; 6 import com.zteits.urbanops.framework.common.util.object.BeanUtils;
@@ -12,10 +13,12 @@ import com.zteits.urbanops.module.garden.dal.dataobject.unitintegraladd.UnitInte @@ -12,10 +13,12 @@ import com.zteits.urbanops.module.garden.dal.dataobject.unitintegraladd.UnitInte
12 import com.zteits.urbanops.module.garden.dal.dataobject.unitintegraltotal.UnitIntegralTotalDO; 13 import com.zteits.urbanops.module.garden.dal.dataobject.unitintegraltotal.UnitIntegralTotalDO;
13 import com.zteits.urbanops.module.garden.dal.mysql.unitintegraladd.UnitIntegralAddMapper; 14 import com.zteits.urbanops.module.garden.dal.mysql.unitintegraladd.UnitIntegralAddMapper;
14 import com.zteits.urbanops.module.garden.dal.mysql.unitintegraltotal.UnitIntegralTotalMapper; 15 import com.zteits.urbanops.module.garden.dal.mysql.unitintegraltotal.UnitIntegralTotalMapper;
  16 +import com.zteits.urbanops.module.garden.dal.redis.IntegralLockCoreRedisDAO;
15 import com.zteits.urbanops.module.garden.service.unitintegraladd.UnitIntegralAddService; 17 import com.zteits.urbanops.module.garden.service.unitintegraladd.UnitIntegralAddService;
16 import com.zteits.urbanops.module.garden.service.unitintegralsub.UnitIntegralSubService; 18 import com.zteits.urbanops.module.garden.service.unitintegralsub.UnitIntegralSubService;
17 import jakarta.annotation.Resource; 19 import jakarta.annotation.Resource;
18 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
  21 +import org.apache.commons.lang3.ObjectUtils;
19 import org.apache.commons.lang3.StringUtils; 22 import org.apache.commons.lang3.StringUtils;
20 import org.redisson.api.RLock; 23 import org.redisson.api.RLock;
21 import org.redisson.api.RedissonClient; 24 import org.redisson.api.RedissonClient;
@@ -55,6 +58,9 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{ @@ -55,6 +58,9 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{
55 private UnitIntegralAddService unitIntegralAddService; 58 private UnitIntegralAddService unitIntegralAddService;
56 @Resource 59 @Resource
57 private RedissonClient redissonClient; 60 private RedissonClient redissonClient;
  61 + @Resource
  62 + private IntegralLockCoreRedisDAO integralLockCoreRedisDAO;
  63 +
58 64
59 // 锁前缀(区分加/减积分锁) 65 // 锁前缀(区分加/减积分锁)
60 private static final String LOCK_PREFIX_INTEGRAL = "integral:"; 66 private static final String LOCK_PREFIX_INTEGRAL = "integral:";
@@ -125,85 +131,78 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{ @@ -125,85 +131,78 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{
125 * @param reqVO 积分增加请求(注意:totalIntegral 为「本次增加积分」) 131 * @param reqVO 积分增加请求(注意:totalIntegral 为「本次增加积分」)
126 */ 132 */
127 @Override 133 @Override
128 - @Transactional(rollbackFor = Exception.class)  
129 public void addUnitIntegral(UnitIntegralSaveReqVO reqVO){ 134 public void addUnitIntegral(UnitIntegralSaveReqVO reqVO){
130 // 1. 参数校验 135 // 1. 参数校验
  136 + if (reqVO == null) {
  137 + throw exception0(BAD_REQUEST.getCode(), "积分增加请求参数不能为空");
  138 + }
131 if (reqVO.getTotalIntegral() <= 0) { 139 if (reqVO.getTotalIntegral() <= 0) {
132 - throw exception0(BAD_REQUEST.getCode(),"本次增加积分必须为正数"); 140 + throw exception0(BAD_REQUEST.getCode(), "本次增加积分必须为正数");
  141 + }
  142 + if (ObjectUtils.isEmpty(reqVO.getUnitId()) || ObjectUtils.isEmpty(reqVO.getStatDate())) {
  143 + throw exception0(BAD_REQUEST.getCode(), "单位ID和统计日期不能为空");
133 } 144 }
134 145
135 - // 2. 构建细粒度锁Key:单位ID + 统计日期 + 操作类型  
136 - String lockKey = buildLockKey(reqVO.getUnitId(), reqVO.getStatDate());  
137 - RLock lock = redissonClient.getLock(lockKey);  
138 -  
139 - // 3. 获取锁(非阻塞,避免线程等待;3秒获取超时,10秒自动过期防死锁)  
140 - boolean lockAcquired = false;  
141 - try {  
142 - lockAcquired = lock.tryLock(3, 10, TimeUnit.SECONDS);  
143 - if (!lockAcquired) {  
144 - String errorMsg = String.format("获取积分增加锁失败,单位ID:%s,统计日期:%s(请稍后重试)", reqVO.getUnitId(), reqVO.getStatDate());  
145 - log.error(errorMsg);  
146 - throw exception0(INTERNAL_SERVER_ERROR.getCode(), errorMsg);  
147 - }  
148 -  
149 - // 2. 构建查询条件  
150 - LambdaQueryWrapper<UnitIntegralTotalDO> queryWrapper = Wrappers.lambdaQuery(UnitIntegralTotalDO.class)  
151 - .eq(UnitIntegralTotalDO::getUnitType, reqVO.getUnitType())  
152 - .eq(UnitIntegralTotalDO::getStatDate, reqVO.getStatDate())  
153 - .eq(UnitIntegralTotalDO::getUnitId, reqVO.getUnitId())  
154 - .eq(UnitIntegralTotalDO::getDeleted, 0);  
155 -  
156 - // 3. 可加行锁(FOR UPDATE)防止多线程同时扣减,保证数据一致性  
157 - UnitIntegralTotalDO unitIntegralTotalDO = unitIntegralTotalMapper.selectOne(queryWrapper);  
158 -  
159 - // 4. 初始化变量(语义清晰,避免冗余)  
160 - int beforeIntegral = 0; // 本次增加前的累计增加积分  
161 - int afterIntegral = 0; // 本次增加后的累计增加积分  
162 - int currentAdd = reqVO.getTotalIntegral(); // 本次增加积分(重命名,语义更准) 146 + // 2. 调用通用锁工具类,加锁执行核心逻辑(参考executeNotify的Runnable风格)
  147 + integralLockCoreRedisDAO.lock(
  148 + reqVO.getUnitId(),
  149 + reqVO.getStatDate(),
  150 + IntegralLockCoreRedisDAO.INTEGRAL_LOCK_TIMEOUT_MILLIS,
  151 + () -> {
  152 + // 3. 锁内二次校验(关键!避免分布式锁并发问题,参考executeNotify的dbTask校验)
  153 + // 场景:两个线程同时通过前置校验,第一个执行完后,第二个拿到锁仍会执行,需校验数据库状态
  154 + LambdaQueryWrapper<UnitIntegralTotalDO> checkWrapper = Wrappers.lambdaQuery(UnitIntegralTotalDO.class)
  155 + .eq(UnitIntegralTotalDO::getUnitId, reqVO.getUnitId())
  156 + .eq(UnitIntegralTotalDO::getStatDate, reqVO.getStatDate())
  157 + .eq(UnitIntegralTotalDO::getUnitType, reqVO.getUnitType())
  158 + .eq(UnitIntegralTotalDO::getDeleted, 0);
  159 + UnitIntegralTotalDO dbTotalDO = unitIntegralTotalMapper.selectOne(checkWrapper);
163 160
164 - // 5. 新增/更新总积分表(核心逻辑)  
165 - if (unitIntegralTotalDO != null) {  
166 - // 5.1 已有记录:更新积分  
167 - beforeIntegral = unitIntegralTotalDO.getTotalAdd();  
168 - int newTotalAdd = beforeIntegral + currentAdd;  
169 - // 更新累计增加积分 + 当前总积分(累计增加 - 累计扣减)  
170 - unitIntegralTotalDO.setTotalAdd(newTotalAdd);  
171 - unitIntegralTotalDO.setTotalIntegral(newTotalAdd - unitIntegralTotalDO.getTotalSub());  
172 - unitIntegralTotalDO.setUpdateTime(LocalDateTime.now());  
173 - unitIntegralTotalDO.setUpdater(String.valueOf(getLoginUserId()));  
174 - unitIntegralTotalMapper.updateById(unitIntegralTotalDO);  
175 - afterIntegral = newTotalAdd; 161 + // 4. 调用带事务的核心执行方法(自注入避免事务失效)
  162 + getSelf().executeAddUnitIntegral0(reqVO, dbTotalDO);
  163 + }
  164 + );
  165 + }
  166 + /**
  167 + * 积分增加核心执行方法(带事务,内部调用)
  168 + */
  169 + @Transactional(rollbackFor = Exception.class)
  170 + public void executeAddUnitIntegral0(UnitIntegralSaveReqVO reqVO, UnitIntegralTotalDO unitIntegralTotalDO) {
  171 + int beforeIntegral = 0; // 本次增加前的累计增加积分
  172 + int afterIntegral = 0; // 本次增加后的累计增加积分
  173 + int currentAdd = reqVO.getTotalIntegral(); // 本次增加积分(重命名,语义更准)
176 174
177 - log.info("更新单位积分成功,单位ID:{},统计日期:{},本次增加:{},累计增加:{}",  
178 - reqVO.getUnitId(), reqVO.getStatDate(), currentAdd, newTotalAdd);  
179 - } else {  
180 - // 5.2 无记录:插入新记录  
181 - UnitIntegralTotalDO saveDO = new UnitIntegralTotalDO();  
182 - BeanUtils.copyProperties(reqVO, saveDO);  
183 - saveDO.setTotalAdd(currentAdd); // 累计增加 = 本次增加  
184 - saveDO.setTotalSub(0); // 初始扣减为0  
185 - saveDO.setTotalIntegral(currentAdd); // 初始总积分 = 本次增加  
186 - unitIntegralTotalMapper.insert(saveDO);  
187 - afterIntegral = currentAdd; 175 + // 5. 新增/更新总积分表(核心逻辑)
  176 + if (unitIntegralTotalDO != null) {
  177 + // 5.1 已有记录:更新积分
  178 + beforeIntegral = unitIntegralTotalDO.getTotalAdd();
  179 + int newTotalAdd = beforeIntegral + currentAdd;
  180 + // 更新累计增加积分 + 当前总积分(累计增加 - 累计扣减)
  181 + unitIntegralTotalDO.setTotalAdd(newTotalAdd);
  182 + unitIntegralTotalDO.setTotalIntegral(newTotalAdd - unitIntegralTotalDO.getTotalSub());
  183 + unitIntegralTotalDO.setUpdateTime(LocalDateTime.now());
  184 + unitIntegralTotalDO.setUpdater(String.valueOf(getLoginUserId()));
  185 + unitIntegralTotalMapper.updateById(unitIntegralTotalDO);
  186 + afterIntegral = newTotalAdd;
188 187
189 - log.info("新增单位积分成功,单位ID:{},统计日期:{},本次增加:{}",  
190 - reqVO.getUnitId(), reqVO.getStatDate(), currentAdd);  
191 - }  
192 - // 5. 新增积分明细  
193 - createAddDetail(reqVO, beforeIntegral, afterIntegral, currentAdd);  
194 - log.info("积分增加成功,单位ID:{},本次增加:{}", reqVO.getUnitId(), currentAdd); 188 + log.info("更新单位积分成功,单位ID:{},统计日期:{},本次增加:{},累计增加:{}",
  189 + reqVO.getUnitId(), reqVO.getStatDate(), currentAdd, newTotalAdd);
  190 + } else {
  191 + // 5.2 无记录:插入新记录
  192 + UnitIntegralTotalDO saveDO = new UnitIntegralTotalDO();
  193 + BeanUtils.copyProperties(reqVO, saveDO);
  194 + saveDO.setTotalAdd(currentAdd); // 累计增加 = 本次增加
  195 + saveDO.setTotalSub(0); // 初始扣减为0
  196 + saveDO.setTotalIntegral(currentAdd); // 初始总积分 = 本次增加
  197 + unitIntegralTotalMapper.insert(saveDO);
  198 + afterIntegral = currentAdd;
195 199
196 - } catch (InterruptedException e) {  
197 - log.error("获取锁被中断,单位ID:{}", reqVO.getUnitId(), e);  
198 - Thread.currentThread().interrupt(); // 恢复中断状态  
199 - throw exception0(INTERNAL_SERVER_ERROR.getCode(), "积分增加操作被中断,请重试");  
200 - } finally {  
201 - // 6. 释放锁(仅当前线程持有锁时释放,避免误删)  
202 - if (lockAcquired && lock.isHeldByCurrentThread()) {  
203 - lock.unlock();  
204 - log.debug("释放积分增加锁,锁Key:{}", lockKey);  
205 - } 200 + log.info("新增单位积分成功,单位ID:{},统计日期:{},本次增加:{}",
  201 + reqVO.getUnitId(), reqVO.getStatDate(), currentAdd);
206 } 202 }
  203 + // 5. 新增积分明细
  204 + createAddDetail(reqVO, beforeIntegral, afterIntegral, currentAdd);
  205 + log.info("积分增加成功,单位ID:{},本次增加:{}", reqVO.getUnitId(), currentAdd);
207 } 206 }
208 /** 207 /**
209 * 封装增加明细创建逻辑 208 * 封装增加明细创建逻辑
@@ -222,81 +221,78 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{ @@ -222,81 +221,78 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{
222 * @param reqVO 积分扣减请求(totalIntegral 为「本次扣减积分」) 221 * @param reqVO 积分扣减请求(totalIntegral 为「本次扣减积分」)
223 */ 222 */
224 @Override 223 @Override
225 - @Transactional(rollbackFor = Exception.class)  
226 public void subUnitIntegral(UnitIntegralSaveReqVO reqVO){ 224 public void subUnitIntegral(UnitIntegralSaveReqVO reqVO){
227 // 1. 前置参数校验 225 // 1. 前置参数校验
  226 + if (reqVO == null) {
  227 + throw exception0(BAD_REQUEST.getCode(), "积分扣减请求参数不能为空");
  228 + }
228 if (reqVO.getTotalIntegral() <= 0) { 229 if (reqVO.getTotalIntegral() <= 0) {
229 - throw exception0(BAD_REQUEST.getCode(),"本次增加积分必须为正数"); 230 + throw exception0(BAD_REQUEST.getCode(), "本次扣减积分必须为正数"); // 修复文案错误
  231 + }
  232 + if (ObjectUtils.isEmpty(reqVO.getUnitId()) || ObjectUtils.isEmpty(reqVO.getStatDate())) {
  233 + throw exception0(BAD_REQUEST.getCode(), "单位ID和统计日期不能为空");
230 } 234 }
231 235
232 - // 2. 构建细粒度锁Key:单位ID + 统计日期  
233 - String lockKey = buildLockKey(reqVO.getUnitId(), reqVO.getStatDate());  
234 - RLock lock = redissonClient.getLock(lockKey); 236 + // 2. 调用通用锁工具类,加锁执行核心逻辑(参考executeNotify的Runnable风格)
  237 + integralLockCoreRedisDAO.lock(
  238 + reqVO.getUnitId(),
  239 + reqVO.getStatDate(),
  240 + IntegralLockCoreRedisDAO.INTEGRAL_LOCK_TIMEOUT_MILLIS,
  241 + () -> {
  242 + // 3. 锁内二次校验(关键!避免分布式锁并发问题,参考executeNotify的dbTask校验)
  243 + LambdaQueryWrapper<UnitIntegralTotalDO> queryWrapper = Wrappers.lambdaQuery(UnitIntegralTotalDO.class)
  244 + .eq(UnitIntegralTotalDO::getUnitType, reqVO.getUnitType())
  245 + .eq(UnitIntegralTotalDO::getStatDate, reqVO.getStatDate())
  246 + .eq(UnitIntegralTotalDO::getUnitId, reqVO.getUnitId())
  247 + .eq(UnitIntegralTotalDO::getDeleted, 0); // 排除已删除的积分记录
  248 + UnitIntegralTotalDO unitIntegralTotalDO = unitIntegralTotalMapper.selectOne(queryWrapper);
  249 + // 4. 校验积分记录是否存在(锁内校验,避免并发删除场景)
  250 + if (unitIntegralTotalDO == null) {
  251 + String errorMsg = String.format("单位积分记录不存在,单位ID:%s,统计日期:%s",
  252 + reqVO.getUnitId(), reqVO.getStatDate());
  253 + log.error(errorMsg);
  254 + throw exception0(BAD_REQUEST.getCode(), errorMsg);
  255 + }
235 256
236 - // 3. 获取锁(非阻塞,避免线程等待;3秒获取超时,10秒自动过期防死锁)  
237 - boolean lockAcquired = false;  
238 - try {  
239 - lockAcquired = lock.tryLock(3, 10, TimeUnit.SECONDS);  
240 - if (!lockAcquired) {  
241 - String errorMsg = String.format("获取积分增加锁失败,单位ID:%s,统计日期:%s(请稍后重试)", reqVO.getUnitId(), reqVO.getStatDate());  
242 - log.error(errorMsg);  
243 - throw exception0(INTERNAL_SERVER_ERROR.getCode(), errorMsg);  
244 - }  
245 - // 2. 构建查询条件  
246 - LambdaQueryWrapper<UnitIntegralTotalDO> queryWrapper = Wrappers.lambdaQuery(UnitIntegralTotalDO.class)  
247 - .eq(UnitIntegralTotalDO::getUnitType, reqVO.getUnitType())  
248 - .eq(UnitIntegralTotalDO::getStatDate, reqVO.getStatDate())  
249 - .eq(UnitIntegralTotalDO::getUnitId, reqVO.getUnitId())  
250 - .eq(UnitIntegralTotalDO::getDeleted, 0); // 排除已删除的积分记录 257 + // 5. 调用带事务的核心扣减方法
  258 + getSelf().executeSubUnitIntegral0(reqVO, unitIntegralTotalDO);
  259 + }
  260 + );
  261 + }
  262 + /**
  263 + * 扣减积分核心执行方法(带事务,内部调用)
  264 + */
  265 + @Transactional(rollbackFor = Exception.class)
  266 + public void executeSubUnitIntegral0(UnitIntegralSaveReqVO reqVO, UnitIntegralTotalDO unitIntegralTotalDO) {
  267 + // 1. 初始化核心变量
  268 + int currentSub = reqVO.getTotalIntegral(); // 本次扣减积分
  269 + int beforeSub = unitIntegralTotalDO.getTotalSub(); // 扣减前累计扣减积分
  270 + int afterSub = beforeSub + currentSub; // 扣减后累计扣减积分
  271 + int currentTotalIntegral = unitIntegralTotalDO.getTotalAdd() - afterSub; // 扣减后总积分
251 272
252 - // 3. 可加行锁(FOR UPDATE)防止多线程同时扣减,保证数据一致性  
253 - //UnitIntegralTotalDO unitIntegralTotalDO = unitIntegralTotalMapper.selectOne(queryWrapper.last("FOR UPDATE"));  
254 - UnitIntegralTotalDO unitIntegralTotalDO = unitIntegralTotalMapper.selectOne(queryWrapper);  
255 - // 4. 校验积分记录是否存在  
256 - if (unitIntegralTotalDO == null) {  
257 - String errorMsg = String.format("单位积分记录不存在,单位ID:%s,统计日期:%s",  
258 - reqVO.getUnitId(), reqVO.getStatDate());  
259 - log.error(errorMsg);  
260 - throw exception0(BAD_REQUEST.getCode(),errorMsg);  
261 - } 273 + // 2. 业务规则校验:扣减后总积分不能为负数
  274 + if (currentTotalIntegral < 0) {
  275 + String errorMsg = String.format("单位积分扣减失败,扣减后总积分为负!单位ID:%s,当前累计增加:%s,本次扣减:%s,累计扣减:%s",
  276 + reqVO.getUnitId(), unitIntegralTotalDO.getTotalAdd(), currentSub, beforeSub);
  277 + log.error(errorMsg);
  278 + throw exception0(BAD_REQUEST.getCode(),errorMsg);
  279 + }
262 280
263 - // 5. 初始化核心变量  
264 - int currentSub = reqVO.getTotalIntegral(); // 本次扣减积分  
265 - int beforeSub = unitIntegralTotalDO.getTotalSub(); // 扣减前累计扣减积分  
266 - int afterSub = beforeSub + currentSub; // 扣减后累计扣减积分  
267 - int currentTotalIntegral = unitIntegralTotalDO.getTotalAdd() - afterSub; // 扣减后总积分 281 + // 3. 更新积分总表(核心扣减逻辑)
  282 + unitIntegralTotalDO.setTotalSub(afterSub); // 更新累计扣减积分
  283 + unitIntegralTotalDO.setTotalIntegral(currentTotalIntegral); // 更新当前总积分
  284 + unitIntegralTotalDO.setUpdateTime(LocalDateTime.now());
  285 + unitIntegralTotalDO.setUpdater(String.valueOf(getLoginUserId()));
  286 + unitIntegralTotalMapper.updateById(unitIntegralTotalDO);
268 287
269 - // 6. 业务规则校验:扣减后总积分不能为负数  
270 - if (currentTotalIntegral < 0) {  
271 - String errorMsg = String.format("单位积分扣减失败,扣减后总积分为负!单位ID:%s,当前累计增加:%s,本次扣减:%s,累计扣减:%s",  
272 - reqVO.getUnitId(), unitIntegralTotalDO.getTotalAdd(), currentSub, beforeSub);  
273 - log.error(errorMsg);  
274 - throw exception0(BAD_REQUEST.getCode(),errorMsg);  
275 - } 288 + log.info("单位积分扣减成功,单位ID:{},统计日期:{},本次扣减:{},扣减前累计扣减:{},扣减后累计扣减:{},扣减后总积分:{}",
  289 + reqVO.getUnitId(), reqVO.getStatDate(), currentSub, beforeSub, afterSub, currentTotalIntegral);
276 290
277 - // 7. 更新积分总表(核心扣减逻辑)  
278 - unitIntegralTotalDO.setTotalSub(afterSub); // 更新累计扣减积分  
279 - unitIntegralTotalDO.setTotalIntegral(currentTotalIntegral); // 更新当前总积分  
280 - unitIntegralTotalDO.setUpdateTime(LocalDateTime.now());  
281 - unitIntegralTotalDO.setUpdater(String.valueOf(getLoginUserId()));  
282 - unitIntegralTotalMapper.updateById(unitIntegralTotalDO);  
283 -  
284 - log.info("单位积分扣减成功,单位ID:{},统计日期:{},本次扣减:{},扣减前累计扣减:{},扣减后累计扣减:{},扣减后总积分:{}",  
285 - reqVO.getUnitId(), reqVO.getStatDate(), currentSub, beforeSub, afterSub, currentTotalIntegral);  
286 -  
287 - // 8. 新增扣减明细  
288 - // 新增减积分明细  
289 - createSubDetail(reqVO, beforeSub, afterSub, currentSub);  
290 - log.info("单位{}减积分成功,本次减{},累计减{},剩余{}",  
291 - reqVO.getUnitId(), currentSub, afterSub, currentSub);  
292 - } catch (InterruptedException e) {  
293 - Thread.currentThread().interrupt();  
294 - throw exception0(INTERNAL_SERVER_ERROR.getCode(), "积分操作被中断,请重试");  
295 - } finally {  
296 - if (lockAcquired && lock.isHeldByCurrentThread()) {  
297 - lock.unlock();  
298 - }  
299 - } 291 + // 8. 新增扣减明细
  292 + // 新增减积分明细
  293 + createSubDetail(reqVO, beforeSub, afterSub, currentSub);
  294 + log.info("单位{}减积分成功,本次减{},累计减{},剩余{}",
  295 + reqVO.getUnitId(), currentSub, afterSub, currentSub);
300 } 296 }
301 297
302 /** 298 /**
@@ -313,4 +309,14 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{ @@ -313,4 +309,14 @@ public class UnitIntegralServiceImpl implements UnitIntegralService{
313 log.info("新增积分扣减明细成功,单位ID:{},明细ID:{}", updateReqVO.getUnitId(), detailVO.getId()); 309 log.info("新增积分扣减明细成功,单位ID:{},明细ID:{}", updateReqVO.getUnitId(), detailVO.getId());
314 } 310 }
315 311
  312 +
  313 + /**
  314 + * 获得自身的代理对象,解决 AOP 生效问题
  315 + *
  316 + * @return 自己
  317 + */
  318 + private UnitIntegralServiceImpl getSelf() {
  319 + return SpringUtil.getBean(getClass());
  320 + }
  321 +
316 } 322 }