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

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

parent 4d1ec91b
......@@ -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);
}
......
......@@ -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());
}
......
......@@ -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();
}
}
......@@ -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();
}
......
......@@ -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();
}
......
......@@ -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();
}
......
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