Ver Fonte

fix: 领券去重不再依赖唯一索引——业务允许用户持有多张同种券,移除DuplicateKeyException兜底与库存回退,领取去重由Redis校验+互斥锁保证

skyline há 3 semanas atrás
pai
commit
0496b89cb8

+ 4 - 18
service/src/main/java/com/kym/service/miniapp/impl/UserCouponServiceImpl.java

@@ -24,7 +24,6 @@ import com.kym.service.admin.CouponService;
 import com.kym.service.miniapp.UserCouponService;
 import com.kym.service.miniapp.UserService;
 import org.springframework.beans.BeanUtils;
-import org.springframework.dao.DuplicateKeyException;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
@@ -179,7 +178,7 @@ public PageBean<UserCouponVo> listUserCoupons(CouponQueryParam params) {
             // 活动
             var activity = activityService.getById(coupon.getActivityId());
 
-            // 先落库(靠(coupon_id,user_id)唯一索引兜底防重),成功后再写Redis,保证两者最终一致
+            // 组装用户优惠券
             var userCoupon = new UserCoupon();
             userCoupon.setActivityId(coupon.getActivityId());
             userCoupon.setActivityName(activity.getName());
@@ -195,22 +194,9 @@ public PageBean<UserCouponVo> listUserCoupons(CouponQueryParam params) {
             userCoupon.setAllowStacke(coupon.getAllowStacke());
             userCoupon.setStatus(UserCoupon.STATUS_有效);
             userCoupon.setRemark(coupon.getRemark());
-            try {
-                save(userCoupon);
-            } catch (DuplicateKeyException e) {
-                // 落库失败(重复领取),回退库存自增
-                try {
-                    DynamicDataSourceContextHolder.push("db-admin");
-                    couponService.lambdaUpdate()
-                            .setSql("claimed_quantity = claimed_quantity - 1")
-                            .eq(Coupon::getId, couponId)
-                            .apply("claimed_quantity > 0")
-                            .update();
-                } finally {
-                    DynamicDataSourceContextHolder.poll();
-                }
-                throw new BusinessException("优惠券已领取,请勿重复领取!");
-            }
+
+            // 先落库,成功后写Redis(业务允许用户持有多张同种券,领取去重由上方Redis校验+互斥锁保证)
+            save(userCoupon);
             redisTemplate.opsForSet().add(RedisKeys.COUPON_ID_TO_USERS, couponId + ":" + userId);
         } finally {
             redisTemplate.delete(lockKey);