Authored by chenjian

改价和下单操作加锁,避免下单的同时改价,导致卖家收入变化

... ... @@ -110,7 +110,9 @@ public class CacheKeyBuilder {
BUYER_ORDER_VIOLATION_PENALTY("ufo:order:buyerOrder:violationPenalty:config",""),
SELLER_DELIVER_LIMIT_TIME("ufo:order:seller:deliver:limitTime","")
SELLER_DELIVER_LIMIT_TIME("ufo:order:seller:deliver:limitTime",""),
ORDER_SKUP_PRICE_LOCK("ufo:order:price:lock:", "skup:{}")
;
private String fix;
... ... @@ -252,4 +254,9 @@ public class CacheKeyBuilder {
return KeyTemp.ORDER_GOODS_DETAIL.builderKey(new Object[]{uid, actor, orderCode});
}
public static RedisKeyBuilder skupPriceLockKey(int skup) {
return KeyTemp.ORDER_SKUP_PRICE_LOCK.builderKey(new Object[]{skup});
}
}
... ...
... ... @@ -25,6 +25,8 @@ public interface ExpiredTime {
int DISTRIBUTED_LOCK_DEPOSIT_GOODS = 5;
int SKUP_PRICE_LOCK_SECONDS = 5;
int SELLER_SALE_GOODS_TAB_LIST_SUMMARY = 300;
int BUYER_ORDER_META = 7200;
... ...
... ... @@ -6,6 +6,8 @@ import com.yoho.core.dal.datasource.annotation.Database;
import com.yoho.core.redis.cluster.operations.serializer.RedisKeyBuilder;
import com.yohobuy.ufo.model.order.common.TabType;
import com.yohoufo.common.alarm.EventBusPublisher;
import com.yohoufo.common.concurrent.lock.RedisLock;
import com.yohoufo.common.concurrent.lock.RedisLockFactory;
import com.yohoufo.common.exception.UfoServiceException;
import com.yohoufo.common.utils.DateUtil;
import com.yohoufo.dal.order.SellerOrderGoodsMapper;
... ... @@ -21,6 +23,7 @@ import com.yohoufo.order.event.SellerOrderPriceChangeEvent;
import com.yohoufo.order.model.dto.*;
import com.yohoufo.order.service.MerchantOrderPaymentService;
import com.yohoufo.order.service.cache.CacheKeyBuilder;
import com.yohoufo.order.service.cache.ExpiredTime;
import com.yohoufo.order.service.proxy.ProductProxyService;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -31,6 +34,7 @@ import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
* Created by jiexiang.wu on 2018/12/21.
... ... @@ -49,6 +53,9 @@ public abstract class AbstractSellerAdjustPriceTaskHandler extends AbstractSelle
@Autowired
protected ProductProxyService productProxyService;
@Autowired
private RedisLockFactory redisLockFactory;
@Override
protected List<FutureTask> getFutureTasks(SellerTaskResult result, SellerTaskDTO<ChangePricePrepareDTO> taskDto) {
ChangePricePrepareDTO cppDto = taskDto.getProcessData();
... ... @@ -81,6 +88,9 @@ public abstract class AbstractSellerAdjustPriceTaskHandler extends AbstractSelle
@Override
public Integer call() throws Exception {
RedisLock skupPriceLock = redisLockFactory.newLock(CacheKeyBuilder.skupPriceLockKey(skupDto.getSkup()), ExpiredTime.SKUP_PRICE_LOCK_SECONDS, TimeUnit.SECONDS);
boolean isSkupPriceLocked = false;
try {
log.info("[{}-{}-{}] handle before sellerOrder:{},before sellerOrderGoods:{},after earnestMoney:{},after income:{}",
uid, taskId, skupDto.getSkup(),
... ... @@ -88,6 +98,13 @@ public abstract class AbstractSellerAdjustPriceTaskHandler extends AbstractSelle
skupDto.getSellerOrderGoods(),
computeResult.getEarnestMoney().getEarnestMoney(),
computeResult.getIncome());
isSkupPriceLocked = skupPriceLock.tryLock();
if(!isSkupPriceLocked) {
log.warn("skup price locked failed before price adjust, skup: {}", skupDto.getSkup());
throw new UfoServiceException(400, "卖家正在调整商品价格,请稍后下单");
}
skupAdjustPriceDBService.update(taskId, salePrice, diffEarnestMoney, computeResult, skupDto);
log.info("[{}-{}-{}] handle success", uid, taskId, skupDto.getSkup());
return skupDto.getSkup();
... ... @@ -99,6 +116,10 @@ public abstract class AbstractSellerAdjustPriceTaskHandler extends AbstractSelle
computeResult.getEarnestMoney().getEarnestMoney(),
computeResult.getIncome(), t);
return null;
} finally {
if (isSkupPriceLocked) {
skupPriceLock.unlock();
}
}
}
}
... ...
... ... @@ -437,7 +437,15 @@ public class ShoppingServiceImpl implements IShoppingService {
SellerOrderGoods psog = checkSkupSellOrNot(uid, shoppingRequest.getSkup());
GoodsPrepareData goodsPrepareData = checkSkupExtraWithlock(uid, psog, true);
checkSkupIsChangePrice(uid, skup);
//checkSkupIsChangePrice(uid, skup); //这个检查无效,改为下面的redis锁
RedisLock skupPriceLock = redisLockFactory.newLock(CacheKeyBuilder.skupPriceLockKey(skup), ExpiredTime.SKUP_PRICE_LOCK_SECONDS, TimeUnit.SECONDS);
boolean isSkupPriceLocked = skupPriceLock.tryLock();
if(!isSkupPriceLocked) {
logger.warn("skup price locked failed before submit, skup: {}", skup);
throw new UfoServiceException(400, "卖家正在调整商品价格,请稍后下单");
}
//活动价格
ActivityPrice activityPrice = checkAndGetActivityPrice(shoppingRequest, psog);
... ... @@ -484,6 +492,9 @@ public class ShoppingServiceImpl implements IShoppingService {
if(locked){
distributedLock.unlock();
}
if(isSkupPriceLocked) {
skupPriceLock.unlock();
}
}
// 订单成功以后,开启15分取消消息
BuyerCancelEvent buyerCancelEvent = BuyerCancelEvent.builder().uid(shoppingRequest.getUid())
... ...
... ... @@ -5,6 +5,8 @@ import com.yohobuy.ufo.model.order.bo.SoldPrdComputeBo;
import com.yohobuy.ufo.model.order.common.Payment;
import com.yohobuy.ufo.model.order.constants.SkupType;
import com.yohobuy.ufo.model.order.req.SingleGoodsChangePriceReq;
import com.yohoufo.common.concurrent.lock.RedisLock;
import com.yohoufo.common.concurrent.lock.RedisLockFactory;
import com.yohoufo.common.exception.UfoServiceException;
import com.yohoufo.dal.order.model.SellerWalletDetail;
import com.yohoufo.order.model.dto.ChangePricePrepareDTO;
... ... @@ -12,6 +14,8 @@ import com.yohoufo.order.model.dto.LifeCycleSellerGoods;
import com.yohoufo.order.model.dto.SellerTaskDTO;
import com.yohoufo.order.model.dto.SellerTaskResult;
import com.yohoufo.order.model.response.OrderSubmitResp;
import com.yohoufo.order.service.cache.CacheKeyBuilder;
import com.yohoufo.order.service.cache.ExpiredTime;
import com.yohoufo.order.service.handler.SellerDecrPriceTaskHandler;
import com.yohoufo.order.service.handler.SellerIncrPriceTaskHandler;
import com.yohoufo.order.service.impl.SellerOrderService;
... ... @@ -21,6 +25,8 @@ import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* Created by chao.chen on 2019/4/12.
*/
... ... @@ -46,6 +52,9 @@ public class ChangePriceService {
@Autowired
private SellerDecrPriceTaskHandler sellerDecrPriceTaskHandler;
@Autowired
private RedisLockFactory redisLockFactory;
private LifeCycleSellerGoods getLifeCycleSellerGoods(int skup){
if (skup <=0){
... ... @@ -121,7 +130,19 @@ public class ChangePriceService {
resp = changePriceOfEntryGoods(req);
}else{
//现有逻辑只支持 非入驻时上架的现货和预售,不支持瑕疵or二手
resp = singleGoodsChangePriceService.changePrice(req);
RedisLock skupPriceLock = redisLockFactory.newLock(CacheKeyBuilder.skupPriceLockKey(req.getSkup()), ExpiredTime.SKUP_PRICE_LOCK_SECONDS, TimeUnit.SECONDS);
boolean isSkupPriceLocked = skupPriceLock.tryLock();
if(!isSkupPriceLocked) {
logger.warn("skup price locked failed before price change, skup: {}", req.getSkup());
throw new UfoServiceException(400, "买家正在下单,不可改价");
}
try {
resp = singleGoodsChangePriceService.changePrice(req);
} finally {
if(isSkupPriceLocked) {
skupPriceLock.unlock();
}
}
}
break;
}
... ...