Browse Source

采用乐观锁更新数据,需要处理更新失败的情况。

Junling Bu 7 years ago
parent
commit
5920f9b1cb
26 changed files with 246 additions and 156 deletions
  1. 5 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAdController.java
  2. 4 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAdminController.java
  3. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminBrandController.java
  4. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminCategoryController.java
  5. 6 6
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminGoodsController.java
  6. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminGrouponController.java
  7. 4 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminIssueController.java
  8. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminKeywordController.java
  9. 28 15
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminOrderController.java
  10. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStorageController.java
  11. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminTopicController.java
  12. 3 1
      litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminUserController.java
  13. 9 3
      litemall-core/src/main/java/org/linlinjava/litemall/core/notify/WxTemplateSender.java
  14. 4 3
      litemall-core/src/main/java/org/linlinjava/litemall/core/util/ResponseUtil.java
  15. 1 1
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallAddressService.java
  16. 1 1
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallCartService.java
  17. 2 4
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallGrouponRulesService.java
  18. 1 1
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallGrouponService.java
  19. 2 6
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallOrderService.java
  20. 3 3
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallUserFormIdService.java
  21. 1 1
      litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallUserService.java
  22. 3 1
      litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxAddressController.java
  23. 9 3
      litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxAuthController.java
  24. 9 3
      litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxCartController.java
  25. 105 66
      litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java
  26. 28 29
      litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxSearchController.java

+ 5 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAdController.java

@@ -72,7 +72,11 @@ public class AdminAdController {
         if(adminId == null){
             return ResponseUtil.unlogin();
         }
-        adService.updateById(ad);
+
+        if(adService.updateById(ad) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
+
         return ResponseUtil.ok(ad);
     }
 

+ 4 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAdminController.java

@@ -124,7 +124,10 @@ public class AdminAdminController {
         String encodedPassword = encoder.encode(rawPassword);
         admin.setPassword(encodedPassword);
 
-        adminService.updateById(admin);
+        if(adminService.updateById(admin) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
+
         return ResponseUtil.ok(admin);
     }
 

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminBrandController.java

@@ -72,7 +72,9 @@ public class AdminBrandController {
         if(adminId == null){
             return ResponseUtil.unlogin();
         }
-        brandService.updateById(brand);
+        if(brandService.updateById(brand) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok(brand);
     }
 

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminCategoryController.java

@@ -74,7 +74,9 @@ public class AdminCategoryController {
         if(adminId == null){
             return ResponseUtil.unlogin();
         }
-        categoryService.updateById(category);
+        if(categoryService.updateById(category) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok();
     }
 

+ 6 - 6
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminGoodsController.java

@@ -101,7 +101,9 @@ public class AdminGoodsController {
             goods.setShareUrl(url);
 
             // 商品基本信息表litemall_goods
-            goodsService.updateById(goods);
+            if(goodsService.updateById(goods) == 0){
+                throw new Exception("跟新数据已失效");
+            }
 
             Integer gid = goods.getId();
             specificationService.deleteByGid(gid);
@@ -109,12 +111,10 @@ public class AdminGoodsController {
             productService.deleteByGid(gid);
 
             // 商品规格表litemall_goods_specification
-            Map<String, Integer> specIds = new HashMap<>();
             for (LitemallGoodsSpecification specification : specifications) {
                 specification.setGoodsId(goods.getId());
                 specification.setAddTime(LocalDateTime.now());
                 specificationService.add(specification);
-                specIds.put(specification.getValue(), specification.getId());
             }
 
             // 商品参数表litemall_goods_attribute
@@ -196,15 +196,15 @@ public class AdminGoodsController {
             //将生成的分享图片地址写入数据库
             String url = qCodeService.createGoodShareImage(goods.getId().toString(), goods.getPicUrl(), goods.getName());
             goods.setShareUrl(url);
-            goodsService.updateById(goods);
+            if(goodsService.updateById(goods) == 0){
+                throw new Exception("跟新数据已失效");
+            }
 
             // 商品规格表litemall_goods_specification
-            Map<String, Integer> specIds = new HashMap<>();
             for (LitemallGoodsSpecification specification : specifications) {
                 specification.setGoodsId(goods.getId());
                 specification.setAddTime(LocalDateTime.now());
                 specificationService.add(specification);
-                specIds.put(specification.getValue(), specification.getId());
             }
 
             // 商品参数表litemall_goods_attribute

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminGrouponController.java

@@ -126,7 +126,9 @@ public class AdminGrouponController {
         grouponRules.setExpireTime(expireTime);
         grouponRules.setPicUrl(goods.getPicUrl());
 
-        rulesService.update(grouponRules);
+        if(rulesService.updateById(grouponRules) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
 
         return ResponseUtil.ok();
     }

+ 4 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminIssueController.java

@@ -72,7 +72,10 @@ public class AdminIssueController {
         if(adminId == null){
             return ResponseUtil.unlogin();
         }
-        issueService.updateById(issue);
+        if(issueService.updateById(issue) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
+
         return ResponseUtil.ok(issue);
     }
 

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminKeywordController.java

@@ -72,7 +72,9 @@ public class AdminKeywordController {
         if(adminId == null){
             return ResponseUtil.unlogin();
         }
-        keywordService.updateById(keywords);
+        if(keywordService.updateById(keywords) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok(keywords);
     }
 

+ 28 - 15
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminOrderController.java

@@ -134,7 +134,9 @@ public class AdminOrderController {
         try {
             // 设置订单取消状态
             order.setOrderStatus(OrderUtil.STATUS_REFUND_CONFIRM);
-            orderService.updateById(order);
+            if(orderService.updateById(order) == 0) {
+                throw new Exception("跟新数据已失效");
+            }
 
             // 商品货品数量增加
             List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
@@ -143,7 +145,9 @@ public class AdminOrderController {
                 LitemallProduct product = productService.findById(productId);
                 Integer number = product.getNumber() + orderGoods.getNumber();
                 product.setNumber(number);
-                productService.updateById(product);
+                if(productService.updateById(product) == 0){
+                    throw new Exception("跟新数据已失效");
+                }
             }
         } catch (Exception ex) {
             txManager.rollback(status);
@@ -204,15 +208,13 @@ public class AdminOrderController {
         order.setShipSn(shipSn);
         order.setShipChannel(shipChannel);
         order.setShipTime(LocalDateTime.now());
-        orderService.updateById(order);
+        if(orderService.updateById(order) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
 
         //TODO 发送邮件和短信通知,这里采用异步发送
-        // 发货会发送通知短信给用户
-        /**
-         *
-         * 您的订单已经发货,快递公司 {1},快递单 {2} ,请注意查收
-         *
-         */
+        // 发货会发送通知短信给用户:          *
+        // "您的订单已经发货,快递公司 {1},快递单 {2} ,请注意查收"
         notifyService.notifySmsTemplate(order.getMobile(), NotifyType.SHIP, new String[]{shipChannel, shipSn});
 
         return ResponseUtil.ok();
@@ -230,7 +232,7 @@ public class AdminOrderController {
      */
     @Scheduled(fixedDelay = 30 * 60 * 1000)
     public void checkOrderUnpaid() {
-        logger.debug(LocalDateTime.now());
+        logger.info("系统开启任务检查订单是否已经超期自动取消订单");
 
         List<LitemallOrder> orderList = orderService.queryUnpaid();
         for (LitemallOrder order : orderList) {
@@ -249,7 +251,9 @@ public class AdminOrderController {
                 // 设置订单已取消状态
                 order.setOrderStatus(OrderUtil.STATUS_AUTO_CANCEL);
                 order.setEndTime(LocalDateTime.now());
-                orderService.updateById(order);
+                if(orderService.updateById(order) == 0){
+                    throw new Exception("跟新数据已失效");
+                }
 
                 // 商品货品数量增加
                 Integer orderId = order.getId();
@@ -259,13 +263,17 @@ public class AdminOrderController {
                     LitemallProduct product = productService.findById(productId);
                     Integer number = product.getNumber() + orderGoods.getNumber();
                     product.setNumber(number);
-                    productService.updateById(product);
+                    if(productService.updateById(product) == 0){
+                        throw new Exception("跟新数据已失效");
+                    }
                 }
             } catch (Exception ex) {
                 txManager.rollback(status);
-                logger.error("系统内部错误", ex);
+                logger.info("订单 ID=" + order.getId() + " 数据已经更新,放弃自动确认收货");
+                return;
             }
             txManager.commit(status);
+            logger.info("订单 ID=" + order.getId() + " 已经超期自动取消订单");
         }
     }
 
@@ -288,7 +296,7 @@ public class AdminOrderController {
      */
     @Scheduled(cron = "0 0 3 * * ?")
     public void checkOrderUnconfirm() {
-        logger.debug(LocalDateTime.now());
+        logger.info("系统开启任务检查订单是否已经超期自动确认收货");
 
         List<LitemallOrder> orderList = orderService.queryUnconfirm();
         for (LitemallOrder order : orderList) {
@@ -301,7 +309,12 @@ public class AdminOrderController {
             // 设置订单已取消状态
             order.setOrderStatus(OrderUtil.STATUS_AUTO_CONFIRM);
             order.setConfirmTime(now);
-            orderService.updateById(order);
+            if(orderService.updateById(order) == 0){
+                logger.info("订单 ID=" + order.getId() + " 数据已经更新,放弃自动确认收货");
+            }
+            else{
+                logger.info("订单 ID=" + order.getId() + " 已经超期自动确认收货");
+            }
         }
     }
 }

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminStorageController.java

@@ -73,7 +73,9 @@ public class AdminStorageController {
         if (adminId == null) {
             return ResponseUtil.unlogin();
         }
-        litemallStorageService.update(litemallStorage);
+        if(litemallStorageService.update(litemallStorage) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok(litemallStorage);
     }
 

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminTopicController.java

@@ -72,7 +72,9 @@ public class AdminTopicController {
         if(adminId == null){
             return ResponseUtil.unlogin();
         }
-        topicService.updateById(topic);
+        if(topicService.updateById(topic) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok(topic);
     }
 

+ 3 - 1
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminUserController.java

@@ -100,7 +100,9 @@ public class AdminUserController {
         String encodedPassword = encoder.encode(password);
         user.setPassword(encodedPassword);
 
-        userService.update(user);
+        if(userService.updateById(user) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok(user);
     }
 }

+ 9 - 3
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/WxTemplateSender.java

@@ -2,6 +2,8 @@ package org.linlinjava.litemall.core.notify;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.linlinjava.litemall.db.domain.LitemallUserFormid;
 import org.linlinjava.litemall.db.service.LitemallUserFormIdService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,11 +15,13 @@ import java.util.List;
  * 微信模版消息通知
  */
 public class WxTemplateSender {
+    private final Log logger = LogFactory.getLog(WxTemplateSender.class);
+
     @Autowired
-    WxMaService wxMaService;
+    private WxMaService wxMaService;
 
     @Autowired
-    LitemallUserFormIdService formIdService;
+    private LitemallUserFormIdService formIdService;
 
     /**
      * 发送微信消息(模板消息),不带跳转
@@ -59,7 +63,9 @@ public class WxTemplateSender {
 
         try {
             wxMaService.getMsgService().sendTemplateMsg(msg);
-            formIdService.updateUserFormId(userFormid);
+            if(formIdService.updateUserFormId(userFormid) == 0){
+                logger.warn("更新数据已失效");
+            }
         } catch (Exception e) {
             e.printStackTrace();
         }

+ 4 - 3
litemall-core/src/main/java/org/linlinjava/litemall/core/util/ResponseUtil.java

@@ -41,17 +41,18 @@ public class ResponseUtil {
         return obj;
     }
 
-
-
     public static Object badArgument(){
         return fail(401, "参数不对");
     }
 
-
     public static Object badArgumentValue(){
         return fail(402, "参数值不对");
     }
 
+    public static Object updatedDateExpired(){
+        return fail(403, "更新数据已经失效");
+    }
+
     public static Object unlogin(){
         return fail(501, "请登录");
     }

+ 1 - 1
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallAddressService.java

@@ -29,7 +29,7 @@ public class LitemallAddressService {
         return addressMapper.insertSelective(address);
     }
 
-    public int update(LitemallAddress address) {
+    public int updateId(LitemallAddress address) {
         return addressMapper.updateWithVersionByPrimaryKeySelective(address.getVersion(), address);
     }
 

+ 1 - 1
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallCartService.java

@@ -25,7 +25,7 @@ public class LitemallCartService {
         cartMapper.insertSelective(cart);
     }
 
-    public int update(LitemallCart cart) {
+    public int updateById(LitemallCart cart) {
         return cartMapper.updateWithVersionByPrimaryKeySelective(cart.getVersion(), cart);
     }
 

+ 2 - 4
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallGrouponRulesService.java

@@ -65,9 +65,7 @@ public class LitemallGrouponRulesService {
      * @return
      */
     public boolean isExpired(LitemallGrouponRules rules) {
-        if (rules == null || rules.getExpireTime().isBefore(LocalDateTime.now()))
-            return true;
-        return false;
+        return (rules == null || rules.getExpireTime().isBefore(LocalDateTime.now()));
     }
 
     /**
@@ -109,7 +107,7 @@ public class LitemallGrouponRulesService {
         mapper.logicalDeleteByPrimaryKey(id);
     }
 
-    public int update(LitemallGrouponRules grouponRules) {
+    public int updateById(LitemallGrouponRules grouponRules) {
         return mapper.updateWithVersionByPrimaryKeySelective(grouponRules.getVersion(), grouponRules);
     }
 }

+ 1 - 1
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallGrouponService.java

@@ -90,7 +90,7 @@ public class LitemallGrouponService {
         return (int) mapper.countByExample(example);
     }
 
-    public int update(LitemallGroupon groupon) {
+    public int updateById(LitemallGroupon groupon) {
         return mapper.updateWithVersionByPrimaryKeySelective(groupon.getVersion(), groupon);
     }
 

+ 2 - 6
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallOrderService.java

@@ -98,10 +98,6 @@ public class LitemallOrderService {
         return (int)orderMapper.countByExample(example);
     }
 
-    public int update(LitemallOrder order) {
-        return orderMapper.updateByPrimaryKeySelective(order);
-    }
-
     public List<LitemallOrder> querySelective(Integer userId, String orderSn, List<Short> orderStatusArray, Integer page, Integer size, String sort, String order) {
         LitemallOrderExample example = new LitemallOrderExample();
         LitemallOrderExample.Criteria criteria = example.createCriteria();
@@ -140,8 +136,8 @@ public class LitemallOrderService {
         return (int)orderMapper.countByExample(example);
     }
 
-    public void updateById(LitemallOrder order) {
-        orderMapper.updateByPrimaryKeySelective(order);
+    public int updateById(LitemallOrder order) {
+        return orderMapper.updateWithVersionByPrimaryKeySelective(order.getVersion(), order);
     }
 
     public void deleteById(Integer id) {

+ 3 - 3
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallUserFormIdService.java

@@ -31,13 +31,13 @@ public class LitemallUserFormIdService {
      *
      * @param userFormid
      */
-    public void updateUserFormId(LitemallUserFormid userFormid) {
+    public int updateUserFormId(LitemallUserFormid userFormid) {
         //更新或者删除缓存
         if (userFormid.getIsprepay() && userFormid.getUseamount() > 1) {
             userFormid.setUseamount(userFormid.getUseamount() - 1);
-            formidMapper.updateWithVersionByPrimaryKey(userFormid.getVersion(), userFormid);
+            return formidMapper.updateWithVersionByPrimaryKey(userFormid.getVersion(), userFormid);
         } else {
-            formidMapper.deleteByPrimaryKey(userFormid.getId());
+            return formidMapper.deleteByPrimaryKey(userFormid.getId());
         }
     }
 

+ 1 - 1
litemall-db/src/main/java/org/linlinjava/litemall/db/service/LitemallUserService.java

@@ -39,7 +39,7 @@ public class LitemallUserService {
         userMapper.insertSelective(user);
     }
 
-    public int update(LitemallUser user) {
+    public int updateById(LitemallUser user) {
         return userMapper.updateWithVersionByPrimaryKeySelective(user.getVersion(), user);
     }
 

+ 3 - 1
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxAddressController.java

@@ -160,7 +160,9 @@ public class WxAddressController {
             addressService.add(address);
         } else {
             address.setUserId(userId);
-            addressService.update(address);
+            if(addressService.updateId(address) == 0){
+                return ResponseUtil.updatedDateExpired();
+            }
         }
         return ResponseUtil.ok(address.getId());
     }

+ 9 - 3
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxAuthController.java

@@ -166,7 +166,9 @@ public class WxAuthController {
         } else {
             user.setLastLoginTime(LocalDateTime.now());
             user.setLastLoginIp(IpUtil.client(request));
-            userService.update(user);
+            if(userService.updateById(user) == 0){
+                return ResponseUtil.updatedDateExpired();
+            }
         }
 
         // token
@@ -333,7 +335,9 @@ public class WxAuthController {
         String encodedPassword = encoder.encode(password);
         user.setPassword(encodedPassword);
 
-        userService.update(user);
+        if(userService.updateById(user) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
 
         return ResponseUtil.ok();
     }
@@ -347,7 +351,9 @@ public class WxAuthController {
         String phone = phoneNumberInfo.getPhoneNumber();
         LitemallUser user = userService.findById(userId);
         user.setMobile(phone);
-        userService.update(user);
+        if(userService.updateById(user) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok();
     }
 }

+ 9 - 3
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxCartController.java

@@ -150,7 +150,9 @@ public class WxCartController {
                 return ResponseUtil.fail(400, "库存不足");
             }
             existCart.setNumber((short) num);
-            cartService.update(existCart);
+            if(cartService.updateById(existCart) == 0){
+                return ResponseUtil.updatedDateExpired();
+            }
         }
 
         return goodscount(userId);
@@ -221,7 +223,9 @@ public class WxCartController {
                 return ResponseUtil.fail(400, "库存不足");
             }
             existCart.setNumber((short) num);
-            cartService.update(existCart);
+            if(cartService.updateById(existCart) == 0){
+                return ResponseUtil.updatedDateExpired();
+            }
         }
 
         return ResponseUtil.ok(existCart != null ? existCart.getId() : cart.getId());
@@ -281,7 +285,9 @@ public class WxCartController {
         }
 
         existCart.setNumber(number.shortValue());
-        cartService.update(existCart);
+        if(cartService.updateById(existCart) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok();
     }
 

+ 105 - 66
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java

@@ -5,6 +5,7 @@ import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
 import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
+import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.constraints.NotNull;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
@@ -426,7 +428,9 @@ public class WxOrderController {
                     throw new RuntimeException("下单的商品货品数量大于库存量");
                 }
                 product.setNumber(remainNumber);
-                productService.updateById(product);
+                if(productService.updateById(product) == 0){
+                    throw new Exception("更新数据已失效");
+                }
             }
 
             //如果是团购项目,添加团购信息
@@ -509,7 +513,9 @@ public class WxOrderController {
             // 设置订单已取消状态
             order.setOrderStatus(OrderUtil.STATUS_CANCEL);
             order.setEndTime(LocalDateTime.now());
-            orderService.updateById(order);
+            if(orderService.updateById(order) == 0){
+                throw new Exception("更新数据已失效");
+            }
 
             // 商品货品数量增加
             List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
@@ -518,7 +524,9 @@ public class WxOrderController {
                 LitemallProduct product = productService.findById(productId);
                 Integer number = product.getNumber() + orderGoods.getNumber();
                 product.setNumber(number);
-                productService.updateById(product);
+                if(productService.updateById(product) == 0){
+                    throw new Exception("更新数据已失效");
+                }
             }
         } catch (Exception ex) {
             txManager.rollback(status);
@@ -603,7 +611,9 @@ public class WxOrderController {
             return ResponseUtil.fail(403, "订单不能支付");
         }
 
-        orderService.updateById(order);
+        if(orderService.updateById(order) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok(result);
     }
 
@@ -623,78 +633,103 @@ public class WxOrderController {
      */
     @PostMapping("pay-notify")
     public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
+        String xmlResult = null;
         try {
-            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
-            WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
+            xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
+        } catch (IOException e) {
+            e.printStackTrace();
+            return WxPayNotifyResponse.fail(e.getMessage());
+        }
 
-            String orderSn = result.getOutTradeNo();
-            String payId = result.getTransactionId();
+        WxPayOrderNotifyResult result = null;
+        try {
+            result = wxPayService.parseOrderNotifyResult(xmlResult);
+        } catch (WxPayException e) {
+            e.printStackTrace();
+            return WxPayNotifyResponse.fail(e.getMessage());
+        }
 
-            // 分转化成元
-            String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
+        logger.info("处理腾讯支付平台的订单支付");
+        logger.info(result);
 
-            LitemallOrder order = orderService.findBySn(orderSn);
-            if (order == null) {
-                throw new Exception("订单不存在 sn=" + orderSn);
-            }
+        String orderSn = result.getOutTradeNo();
+        String payId = result.getTransactionId();
 
-            // 检查这个订单是否已经处理过
-            if (OrderUtil.isPayStatus(order) && order.getPayId() != null) {
-                return WxPayNotifyResponse.success("处理成功!");
+        // 分转化成元
+        String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
+        LitemallOrder order = orderService.findBySn(orderSn);
+        if (order == null) {
+            return WxPayNotifyResponse.fail("订单不存在 sn=" + orderSn);
+        }
+
+        // 检查这个订单是否已经处理过
+        if (OrderUtil.isPayStatus(order) && order.getPayId() != null) {
+            return WxPayNotifyResponse.success("订单已经处理成功!");
+        }
+
+        // 检查支付订单金额
+        if (!totalFee.equals(order.getActualPrice().toString())) {
+            return WxPayNotifyResponse.fail(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
+        }
+
+        order.setPayId(payId);
+        order.setPayTime(LocalDateTime.now());
+        order.setOrderStatus(OrderUtil.STATUS_PAY);
+        if (orderService.updateById(order) == 0) {
+            // 这里可能存在这样一个问题,用户支付和系统自动取消订单发生在同时
+            // 如果数据库首先因为系统自动取消订单而更新了订单状态;
+            // 此时用户支付完成回调这里也要更新数据库,而由于乐观锁机制这里的更新会失败
+            // 因此,这里会重新读取数据库检查状态是否是订单自动取消,如果是则更新成支付状态。
+            order = orderService.findBySn(orderSn);
+            int updated = 0;
+            if(OrderUtil.isAutoCancelStatus(order)){
+                order.setPayId(payId);
+                order.setPayTime(LocalDateTime.now());
+                order.setOrderStatus(OrderUtil.STATUS_PAY);
+                updated = orderService.updateById(order);
             }
 
-            // 检查支付订单金额
-            if (!totalFee.equals(order.getActualPrice().toString())) {
-                throw new Exception(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
+            // 如果updated是0,那么数据库更新失败
+            if(updated == 0) {
+                return WxPayNotifyResponse.fail("更新数据已失效");
             }
+        }
 
-            order.setPayId(payId);
-            order.setPayTime(LocalDateTime.now());
-            order.setOrderStatus(OrderUtil.STATUS_PAY);
-            orderService.updateById(order);
-
-            //  支付成功,有团购信息,更新团购信息
-            LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
-            if (groupon != null) {
-                LitemallGrouponRules grouponRules = grouponRulesService.queryById(groupon.getRulesId());
+        //  支付成功,有团购信息,更新团购信息
+        LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
+        if (groupon != null) {
+            LitemallGrouponRules grouponRules = grouponRulesService.queryById(groupon.getRulesId());
 
-                //仅当发起者才创建分享图片
-                if (groupon.getGrouponId() == 0) {
-                    String url = qCodeService.createGrouponShareImage(grouponRules.getGoodsName(), grouponRules.getPicUrl(), groupon);
-                    groupon.setShareUrl(url);
-                }
-                groupon.setPayed(true);
-                grouponService.update(groupon);
+            //仅当发起者才创建分享图片
+            if (groupon.getGrouponId() == 0) {
+                String url = qCodeService.createGrouponShareImage(grouponRules.getGoodsName(), grouponRules.getPicUrl(), groupon);
+                groupon.setShareUrl(url);
+            }
+            groupon.setPayed(true);
+            if (grouponService.updateById(groupon) == 0) {
+                return WxPayNotifyResponse.fail("更新数据已失效");
             }
-
-            //TODO 发送邮件和短信通知,这里采用异步发送
-            // 订单支付成功以后,会发送短信给用户,以及发送邮件给管理员
-            notifyService.notifyMail("新订单通知", order.toString());
-            /**
-             * 这里微信的短信平台对参数长度有限制,所以将订单号只截取后6位
-             *
-             */
-            notifyService.notifySmsTemplateSync(order.getMobile(), NotifyType.PAY_SUCCEED, new String[]{orderSn.substring(8, 14)});
-
-            /**
-             * 请依据自己的模版消息配置更改参数
-             */
-            String[] parms = new String[]{
-                    order.getOrderSn(),
-                    order.getOrderPrice().toString(),
-                    DateTimeUtil.getDateTimeDisplayString(order.getAddTime()),
-                    order.getConsignee(),
-                    order.getMobile(),
-                    order.getAddress()
-            };
-
-            notifyService.notifyWxTemplate(result.getOpenid(), NotifyType.PAY_SUCCEED, parms, "pages/index/index?orderId=" + order.getId());
-
-            return WxPayNotifyResponse.success("处理成功!");
-        } catch (Exception e) {
-            logger.error("微信回调结果异常,异常原因 " + e.getMessage());
-            return WxPayNotifyResponse.fail(e.getMessage());
         }
+
+        //TODO 发送邮件和短信通知,这里采用异步发送
+        // 订单支付成功以后,会发送短信给用户,以及发送邮件给管理员
+        notifyService.notifyMail("新订单通知", order.toString());
+        // 这里微信的短信平台对参数长度有限制,所以将订单号只截取后6位
+        notifyService.notifySmsTemplateSync(order.getMobile(), NotifyType.PAY_SUCCEED, new String[]{orderSn.substring(8, 14)});
+
+        // 请依据自己的模版消息配置更改参数
+        String[] parms = new String[]{
+                order.getOrderSn(),
+                order.getOrderPrice().toString(),
+                DateTimeUtil.getDateTimeDisplayString(order.getAddTime()),
+                order.getConsignee(),
+                order.getMobile(),
+                order.getAddress()
+        };
+
+        notifyService.notifyWxTemplate(result.getOpenid(), NotifyType.PAY_SUCCEED, parms, "pages/index/index?orderId=" + order.getId());
+
+        return WxPayNotifyResponse.success("处理成功!");
     }
 
     /**
@@ -733,7 +768,9 @@ public class WxOrderController {
 
         // 设置订单申请退款状态
         order.setOrderStatus(OrderUtil.STATUS_REFUND);
-        orderService.updateById(order);
+        if(orderService.updateById(order) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
 
         //TODO 发送邮件和短信通知,这里采用异步发送
         // 有用户申请退款,邮件通知运营人员
@@ -778,7 +815,9 @@ public class WxOrderController {
 
         order.setOrderStatus(OrderUtil.STATUS_CONFIRM);
         order.setConfirmTime(LocalDateTime.now());
-        orderService.updateById(order);
+        if(orderService.updateById(order) == 0){
+            return ResponseUtil.updatedDateExpired();
+        }
         return ResponseUtil.ok();
     }
 

+ 28 - 29
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxSearchController.java

@@ -27,23 +27,23 @@ public class WxSearchController {
 
     /**
      * 搜索页面信息
-     *
+     * <p>
      * 如果用户已登录,则给出用户历史搜索记录。
      *
      * @param userId 用户ID
      * @return 搜索页面信息
-     *   成功则
-     *  {
-     *      errno: 0,
-     *      errmsg: '成功',
-     *      data:
-     *      {
-     *          defaultKeyword: xxx,
-     *          historyKeywordList: xxx,
-     *          hotKeywordList: xxx
-     *      }
-     *  }
-     *  失败则 { errno: XXX, errmsg: XXX }
+     * 成功则
+     * {
+     * errno: 0,
+     * errmsg: '成功',
+     * data:
+     * {
+     * defaultKeyword: xxx,
+     * historyKeywordList: xxx,
+     * hotKeywordList: xxx
+     * }
+     * }
+     * 失败则 { errno: XXX, errmsg: XXX }
      */
     @GetMapping("index")
     public Object index(@LoginUser Integer userId) {
@@ -53,11 +53,10 @@ public class WxSearchController {
         List<LitemallKeyword> hotKeywordList = keywordsService.queryHots();
 
         List<LitemallSearchHistory> historyList = null;
-        if(userId != null) {
+        if (userId != null) {
             //取出用户历史关键字
             historyList = searchHistoryService.queryByUid(userId);
-        }
-        else {
+        } else {
             historyList = new ArrayList<>(0);
         }
 
@@ -70,18 +69,18 @@ public class WxSearchController {
 
     /**
      * 关键字提醒
-     *
+     * <p>
      * 当用户输入关键字一部分时,可以推荐系统中合适的关键字。
      *
      * @param keyword 关键字
      * @return 合适的关键字
-     *   成功则
-     *  {
-     *      errno: 0,
-     *      errmsg: '成功',
-     *      data: xxx
-     *  }
-     *   失败则 { errno: XXX, errmsg: XXX }
+     * 成功则
+     * {
+     * errno: 0,
+     * errmsg: '成功',
+     * data: xxx
+     * }
+     * 失败则 { errno: XXX, errmsg: XXX }
      */
     @GetMapping("helper")
     public Object helper(@NotEmpty String keyword,
@@ -91,24 +90,24 @@ public class WxSearchController {
         String[] keys = new String[keywordsList.size()];
         int index = 0;
         for (LitemallKeyword key : keywordsList) {
-           keys[index++] = key.getKeyword();
+            keys[index++] = key.getKeyword();
         }
         return ResponseUtil.ok(keys);
     }
 
     /**
      * 关键字清理
-     *
+     * <p>
      * 当用户输入关键字一部分时,可以推荐系统中合适的关键字。
      *
      * @param userId 用户ID
      * @return 清理是否成功
-     *   成功则 { errno: 0, errmsg: '成功' }
-     *   失败则 { errno: XXX, errmsg: XXX }
+     * 成功则 { errno: 0, errmsg: '成功' }
+     * 失败则 { errno: XXX, errmsg: XXX }
      */
     @PostMapping("clearhistory")
     public Object clearhistory(@LoginUser Integer userId) {
-        if(userId == null){
+        if (userId == null) {
             return ResponseUtil.unlogin();
         }