Commit 5920f9b1 authored by Junling Bu's avatar Junling Bu
Browse files

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

parent 4d1ec91b
...@@ -39,7 +39,7 @@ public class LitemallUserService { ...@@ -39,7 +39,7 @@ public class LitemallUserService {
userMapper.insertSelective(user); userMapper.insertSelective(user);
} }
public int update(LitemallUser user) { public int updateById(LitemallUser user) {
return userMapper.updateWithVersionByPrimaryKeySelective(user.getVersion(), user); return userMapper.updateWithVersionByPrimaryKeySelective(user.getVersion(), user);
} }
......
...@@ -160,7 +160,9 @@ public class WxAddressController { ...@@ -160,7 +160,9 @@ public class WxAddressController {
addressService.add(address); addressService.add(address);
} else { } else {
address.setUserId(userId); address.setUserId(userId);
addressService.update(address); if(addressService.updateId(address) == 0){
return ResponseUtil.updatedDateExpired();
}
} }
return ResponseUtil.ok(address.getId()); return ResponseUtil.ok(address.getId());
} }
......
...@@ -166,7 +166,9 @@ public class WxAuthController { ...@@ -166,7 +166,9 @@ public class WxAuthController {
} else { } else {
user.setLastLoginTime(LocalDateTime.now()); user.setLastLoginTime(LocalDateTime.now());
user.setLastLoginIp(IpUtil.client(request)); user.setLastLoginIp(IpUtil.client(request));
userService.update(user); if(userService.updateById(user) == 0){
return ResponseUtil.updatedDateExpired();
}
} }
// token // token
...@@ -333,7 +335,9 @@ public class WxAuthController { ...@@ -333,7 +335,9 @@ public class WxAuthController {
String encodedPassword = encoder.encode(password); String encodedPassword = encoder.encode(password);
user.setPassword(encodedPassword); user.setPassword(encodedPassword);
userService.update(user); if(userService.updateById(user) == 0){
return ResponseUtil.updatedDateExpired();
}
return ResponseUtil.ok(); return ResponseUtil.ok();
} }
...@@ -347,7 +351,9 @@ public class WxAuthController { ...@@ -347,7 +351,9 @@ public class WxAuthController {
String phone = phoneNumberInfo.getPhoneNumber(); String phone = phoneNumberInfo.getPhoneNumber();
LitemallUser user = userService.findById(userId); LitemallUser user = userService.findById(userId);
user.setMobile(phone); user.setMobile(phone);
userService.update(user); if(userService.updateById(user) == 0){
return ResponseUtil.updatedDateExpired();
}
return ResponseUtil.ok(); return ResponseUtil.ok();
} }
} }
...@@ -150,7 +150,9 @@ public class WxCartController { ...@@ -150,7 +150,9 @@ public class WxCartController {
return ResponseUtil.fail(400, "库存不足"); return ResponseUtil.fail(400, "库存不足");
} }
existCart.setNumber((short) num); existCart.setNumber((short) num);
cartService.update(existCart); if(cartService.updateById(existCart) == 0){
return ResponseUtil.updatedDateExpired();
}
} }
return goodscount(userId); return goodscount(userId);
...@@ -221,7 +223,9 @@ public class WxCartController { ...@@ -221,7 +223,9 @@ public class WxCartController {
return ResponseUtil.fail(400, "库存不足"); return ResponseUtil.fail(400, "库存不足");
} }
existCart.setNumber((short) num); existCart.setNumber((short) num);
cartService.update(existCart); if(cartService.updateById(existCart) == 0){
return ResponseUtil.updatedDateExpired();
}
} }
return ResponseUtil.ok(existCart != null ? existCart.getId() : cart.getId()); return ResponseUtil.ok(existCart != null ? existCart.getId() : cart.getId());
...@@ -281,7 +285,9 @@ public class WxCartController { ...@@ -281,7 +285,9 @@ public class WxCartController {
} }
existCart.setNumber(number.shortValue()); existCart.setNumber(number.shortValue());
cartService.update(existCart); if(cartService.updateById(existCart) == 0){
return ResponseUtil.updatedDateExpired();
}
return ResponseUtil.ok(); return ResponseUtil.ok();
} }
......
...@@ -5,6 +5,7 @@ import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; ...@@ -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.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
...@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.*; ...@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
...@@ -426,7 +428,9 @@ public class WxOrderController { ...@@ -426,7 +428,9 @@ public class WxOrderController {
throw new RuntimeException("下单的商品货品数量大于库存量"); throw new RuntimeException("下单的商品货品数量大于库存量");
} }
product.setNumber(remainNumber); product.setNumber(remainNumber);
productService.updateById(product); if(productService.updateById(product) == 0){
throw new Exception("更新数据已失效");
}
} }
//如果是团购项目,添加团购信息 //如果是团购项目,添加团购信息
...@@ -509,7 +513,9 @@ public class WxOrderController { ...@@ -509,7 +513,9 @@ public class WxOrderController {
// 设置订单已取消状态 // 设置订单已取消状态
order.setOrderStatus(OrderUtil.STATUS_CANCEL); order.setOrderStatus(OrderUtil.STATUS_CANCEL);
order.setEndTime(LocalDateTime.now()); order.setEndTime(LocalDateTime.now());
orderService.updateById(order); if(orderService.updateById(order) == 0){
throw new Exception("更新数据已失效");
}
// 商品货品数量增加 // 商品货品数量增加
List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId); List<LitemallOrderGoods> orderGoodsList = orderGoodsService.queryByOid(orderId);
...@@ -518,7 +524,9 @@ public class WxOrderController { ...@@ -518,7 +524,9 @@ public class WxOrderController {
LitemallProduct product = productService.findById(productId); LitemallProduct product = productService.findById(productId);
Integer number = product.getNumber() + orderGoods.getNumber(); Integer number = product.getNumber() + orderGoods.getNumber();
product.setNumber(number); product.setNumber(number);
productService.updateById(product); if(productService.updateById(product) == 0){
throw new Exception("更新数据已失效");
}
} }
} catch (Exception ex) { } catch (Exception ex) {
txManager.rollback(status); txManager.rollback(status);
...@@ -603,7 +611,9 @@ public class WxOrderController { ...@@ -603,7 +611,9 @@ public class WxOrderController {
return ResponseUtil.fail(403, "订单不能支付"); return ResponseUtil.fail(403, "订单不能支付");
} }
orderService.updateById(order); if(orderService.updateById(order) == 0){
return ResponseUtil.updatedDateExpired();
}
return ResponseUtil.ok(result); return ResponseUtil.ok(result);
} }
...@@ -623,78 +633,103 @@ public class WxOrderController { ...@@ -623,78 +633,103 @@ public class WxOrderController {
*/ */
@PostMapping("pay-notify") @PostMapping("pay-notify")
public Object payNotify(HttpServletRequest request, HttpServletResponse response) { public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
String xmlResult = null;
try { try {
String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding()); xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult); } catch (IOException e) {
e.printStackTrace();
return WxPayNotifyResponse.fail(e.getMessage());
}
String orderSn = result.getOutTradeNo(); WxPayOrderNotifyResult result = null;
String payId = result.getTransactionId(); try {
result = wxPayService.parseOrderNotifyResult(xmlResult);
} catch (WxPayException e) {
e.printStackTrace();
return WxPayNotifyResponse.fail(e.getMessage());
}
// 分转化成元 logger.info("处理腾讯支付平台的订单支付");
String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee()); logger.info(result);
LitemallOrder order = orderService.findBySn(orderSn); String orderSn = result.getOutTradeNo();
if (order == null) { String payId = result.getTransactionId();
throw new Exception("订单不存在 sn=" + orderSn);
}
// 检查这个订单是否已经处理过 // 分转化成元
if (OrderUtil.isPayStatus(order) && order.getPayId() != null) { String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
return WxPayNotifyResponse.success("处理成功!"); 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);
} }
// 检查支付订单金额 // 如果updated是0,那么数据库更新失败
if (!totalFee.equals(order.getActualPrice().toString())) { if(updated == 0) {
throw new Exception(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee); return WxPayNotifyResponse.fail("更新数据已失效");
} }
}
order.setPayId(payId); // 支付成功,有团购信息,更新团购信息
order.setPayTime(LocalDateTime.now()); LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
order.setOrderStatus(OrderUtil.STATUS_PAY); if (groupon != null) {
orderService.updateById(order); 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) { if (groupon.getGrouponId() == 0) {
String url = qCodeService.createGrouponShareImage(grouponRules.getGoodsName(), grouponRules.getPicUrl(), groupon); String url = qCodeService.createGrouponShareImage(grouponRules.getGoodsName(), grouponRules.getPicUrl(), groupon);
groupon.setShareUrl(url); groupon.setShareUrl(url);
} }
groupon.setPayed(true); groupon.setPayed(true);
grouponService.update(groupon); 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 { ...@@ -733,7 +768,9 @@ public class WxOrderController {
// 设置订单申请退款状态 // 设置订单申请退款状态
order.setOrderStatus(OrderUtil.STATUS_REFUND); order.setOrderStatus(OrderUtil.STATUS_REFUND);
orderService.updateById(order); if(orderService.updateById(order) == 0){
return ResponseUtil.updatedDateExpired();
}
//TODO 发送邮件和短信通知,这里采用异步发送 //TODO 发送邮件和短信通知,这里采用异步发送
// 有用户申请退款,邮件通知运营人员 // 有用户申请退款,邮件通知运营人员
...@@ -778,7 +815,9 @@ public class WxOrderController { ...@@ -778,7 +815,9 @@ public class WxOrderController {
order.setOrderStatus(OrderUtil.STATUS_CONFIRM); order.setOrderStatus(OrderUtil.STATUS_CONFIRM);
order.setConfirmTime(LocalDateTime.now()); order.setConfirmTime(LocalDateTime.now());
orderService.updateById(order); if(orderService.updateById(order) == 0){
return ResponseUtil.updatedDateExpired();
}
return ResponseUtil.ok(); return ResponseUtil.ok();
} }
......
...@@ -27,23 +27,23 @@ public class WxSearchController { ...@@ -27,23 +27,23 @@ public class WxSearchController {
/** /**
* 搜索页面信息 * 搜索页面信息
* * <p>
* 如果用户已登录,则给出用户历史搜索记录。 * 如果用户已登录,则给出用户历史搜索记录。
* *
* @param userId 用户ID * @param userId 用户ID
* @return 搜索页面信息 * @return 搜索页面信息
* 成功则 * 成功则
* { * {
* errno: 0, * errno: 0,
* errmsg: '成功', * errmsg: '成功',
* data: * data:
* { * {
* defaultKeyword: xxx, * defaultKeyword: xxx,
* historyKeywordList: xxx, * historyKeywordList: xxx,
* hotKeywordList: xxx * hotKeywordList: xxx
* } * }
* } * }
* 失败则 { errno: XXX, errmsg: XXX } * 失败则 { errno: XXX, errmsg: XXX }
*/ */
@GetMapping("index") @GetMapping("index")
public Object index(@LoginUser Integer userId) { public Object index(@LoginUser Integer userId) {
...@@ -53,11 +53,10 @@ public class WxSearchController { ...@@ -53,11 +53,10 @@ public class WxSearchController {
List<LitemallKeyword> hotKeywordList = keywordsService.queryHots(); List<LitemallKeyword> hotKeywordList = keywordsService.queryHots();
List<LitemallSearchHistory> historyList = null; List<LitemallSearchHistory> historyList = null;
if(userId != null) { if (userId != null) {
//取出用户历史关键字 //取出用户历史关键字
historyList = searchHistoryService.queryByUid(userId); historyList = searchHistoryService.queryByUid(userId);
} } else {
else {
historyList = new ArrayList<>(0); historyList = new ArrayList<>(0);
} }
...@@ -70,18 +69,18 @@ public class WxSearchController { ...@@ -70,18 +69,18 @@ public class WxSearchController {
/** /**
* 关键字提醒 * 关键字提醒
* * <p>
* 当用户输入关键字一部分时,可以推荐系统中合适的关键字。 * 当用户输入关键字一部分时,可以推荐系统中合适的关键字。
* *
* @param keyword 关键字 * @param keyword 关键字
* @return 合适的关键字 * @return 合适的关键字
* 成功则 * 成功则
* { * {
* errno: 0, * errno: 0,
* errmsg: '成功', * errmsg: '成功',
* data: xxx * data: xxx
* } * }
* 失败则 { errno: XXX, errmsg: XXX } * 失败则 { errno: XXX, errmsg: XXX }
*/ */
@GetMapping("helper") @GetMapping("helper")
public Object helper(@NotEmpty String keyword, public Object helper(@NotEmpty String keyword,
...@@ -91,24 +90,24 @@ public class WxSearchController { ...@@ -91,24 +90,24 @@ public class WxSearchController {
String[] keys = new String[keywordsList.size()]; String[] keys = new String[keywordsList.size()];
int index = 0; int index = 0;
for (LitemallKeyword key : keywordsList) { for (LitemallKeyword key : keywordsList) {
keys[index++] = key.getKeyword(); keys[index++] = key.getKeyword();
} }
return ResponseUtil.ok(keys); return ResponseUtil.ok(keys);
} }
/** /**
* 关键字清理 * 关键字清理
* * <p>
* 当用户输入关键字一部分时,可以推荐系统中合适的关键字。 * 当用户输入关键字一部分时,可以推荐系统中合适的关键字。
* *
* @param userId 用户ID * @param userId 用户ID
* @return 清理是否成功 * @return 清理是否成功
* 成功则 { errno: 0, errmsg: '成功' } * 成功则 { errno: 0, errmsg: '成功' }
* 失败则 { errno: XXX, errmsg: XXX } * 失败则 { errno: XXX, errmsg: XXX }
*/ */
@PostMapping("clearhistory") @PostMapping("clearhistory")
public Object clearhistory(@LoginUser Integer userId) { public Object clearhistory(@LoginUser Integer userId) {
if(userId == null){ if (userId == null) {
return ResponseUtil.unlogin(); return ResponseUtil.unlogin();
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment