Commit 18ad952c authored by 杨锐's avatar 杨锐

redis分布式锁,处理/user/login/fast并发问题,导致MySQLIntegrityConstraintViolationException

parent 9ca25373
......@@ -27,7 +27,6 @@ import cn.quantgroup.xyqb.service.user.UserCenterService;
import cn.quantgroup.xyqb.service.wechat.IWechatService;
import cn.quantgroup.xyqb.session.XyqbSessionContextHolder;
import cn.quantgroup.xyqb.util.IpUtil;
import cn.quantgroup.xyqb.util.MqUtils;
import cn.quantgroup.xyqb.util.PasswordUtil;
import cn.quantgroup.xyqb.util.ValidationUtil;
import com.alibaba.fastjson.JSON;
......@@ -185,25 +184,7 @@ public class UserController implements IBaseController {
String verificationCode = successResult.getMsg();
// 执行短信验证码检查
verifyPhoneAndCode(phoneNo, verificationCode);
User user = userService.findByPhoneWithCache(phoneNo);
if (user != null && !user.getEnable()) {
log.info("用户不存在,或者已经注销,phoneNo:{}", phoneNo);
return JsonResult.buildErrorStateResult("登录失败", null);
}
if (user == null) {
// Service层会负责发送注册消息到LoanVest
user = userRegisterService.register(phoneNo, channelId, createdFrom, appChannel, btRegisterChannelId, dimension);
if (user == null) {
throw new UserNotExistException("用户未找到");
}
//广点通转化注册 - 发送消息 - 方法内过滤
MqUtils.sendRegisterMessageForGdt(phoneNo, clickId);
}
if (!wechatRelateUserIfNecessary(user, request)) {
return JsonResult.buildErrorStateResult("登录时微信关联失败", null);
}
LoginProperties loginProperties = new LoginProperties("", 3, channelId, createdFrom, appChannel, merchant.getId(), merchant.getName());
return new JsonResult(sessionService.createSession(user, loginProperties));
return userService.loginFast(channelId, appChannel, createdFrom, btRegisterChannelId, dimension, clickId, request, merchant, phoneNo);
}
/**
......
package cn.quantgroup.xyqb.service.user;
import cn.quantgroup.xyqb.entity.Merchant;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.UserInfo;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
......@@ -67,4 +70,8 @@ public interface IUserService {
* @param phoneNo 根据手机号
*/
void userCacheEvict(String uuid, String phoneNo);
JsonResult loginFast(Long channelId, String appChannel, Long createdFrom, Long btRegisterChannelId,
String dimension, String clickId, HttpServletRequest request, Merchant merchant,
String phoneNo);
}
......@@ -2,22 +2,25 @@ package cn.quantgroup.xyqb.service.user.impl;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.aspect.lock.RedisLock;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.entity.UserDetail;
import cn.quantgroup.xyqb.entity.UserHashMapping;
import cn.quantgroup.xyqb.entity.UserHashPhoneNoIdNoMapping;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.entity.*;
import cn.quantgroup.xyqb.event.PhoneNoUpdateEvent;
import cn.quantgroup.xyqb.exception.DataException;
import cn.quantgroup.xyqb.exception.UserNotExistException;
import cn.quantgroup.xyqb.model.FindByMd5Enum;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.LoginProperties;
import cn.quantgroup.xyqb.model.UserInfo;
import cn.quantgroup.xyqb.repository.IUserHashMappingRepository;
import cn.quantgroup.xyqb.repository.IUserHashPhoneNoIdNoMappingRepository;
import cn.quantgroup.xyqb.repository.IUserRepository;
import cn.quantgroup.xyqb.service.register.IUserRegisterService;
import cn.quantgroup.xyqb.service.session.ISessionService;
import cn.quantgroup.xyqb.service.user.IUserDetailService;
import cn.quantgroup.xyqb.service.user.IUserService;
import cn.quantgroup.xyqb.util.HashUtil;
import cn.quantgroup.xyqb.util.PasswordUtil;
import cn.quantgroup.xyqb.util.ValidationUtil;
import cn.quantgroup.xyqb.service.wechat.IWechatService;
import cn.quantgroup.xyqb.util.*;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
......@@ -33,11 +36,9 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
......@@ -45,7 +46,7 @@ import java.util.concurrent.TimeUnit;
*/
@Service
@Slf4j
public class UserServiceImpl implements IUserService {
public class UserServiceImpl implements IUserService, IBaseController {
@Autowired
private RedisTemplate<String, String> stringRedisTemplate;
......@@ -64,6 +65,14 @@ public class UserServiceImpl implements IUserService {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Resource
private IUserRegisterService userRegisterService;
@Autowired
private IWechatService wechatService;
@Autowired
private ISessionService sessionService;
@Override
@Cacheable(value = "usercache", key = "'xyqbuser' + #phone", unless = "#result == null", cacheManager = "cacheManager")
......@@ -120,7 +129,6 @@ public class UserServiceImpl implements IUserService {
}
@Override
@RedisLock(prefix = "lock:user:find:by:phone:", key = "#this[0]")
@Cacheable(value = "usercache", key = "'xyqbuser' + #phone", unless = "#result == null", cacheManager = "cacheManager")
public User findByPhoneWithCache(String phone) {
return userRepository.findByPhoneNo(phone);
......@@ -263,4 +271,57 @@ public class UserServiceImpl implements IUserService {
log.info("清理用户缓存成功,uuid:{},phoneNo:{}", uuid, phoneNo);
}
@Override
@RedisLock(prefix = "lock:login:fast:", key = "#this[8]")
public JsonResult loginFast(Long channelId, String appChannel, Long createdFrom, Long btRegisterChannelId,
String dimension, String clickId, HttpServletRequest request, Merchant merchant, String phoneNo) {
User user = findByPhoneWithCache(phoneNo);
if (user != null && !user.getEnable()) {
log.info("用户不存在,或者已经注销,phoneNo:{}", phoneNo);
return JsonResult.buildErrorStateResult("登录失败", null);
}
if (user == null) {
// Service层会负责发送注册消息到LoanVest
user = userRegisterService.register(phoneNo, channelId, createdFrom, appChannel, btRegisterChannelId, dimension);
if (user == null) {
throw new UserNotExistException("用户未找到");
}
//广点通转化注册 - 发送消息 - 方法内过滤
MqUtils.sendRegisterMessageForGdt(phoneNo, clickId);
}
if (!wechatRelateUserIfNecessary(user, request)) {
return JsonResult.buildErrorStateResult("登录时微信关联失败", null);
}
LoginProperties loginProperties = new LoginProperties("", 3, channelId, createdFrom, appChannel, merchant.getId(), merchant.getName());
return new JsonResult(sessionService.createSession(user, loginProperties));
}
/**
* 如果必要的话,关联用户和微信
*
* @param user - 用户标识
* @param request - 当前请求
* @return true - 继续登录,false - 微信关联失败,重新登录
*/
private boolean wechatRelateUserIfNecessary(User user, HttpServletRequest request) {
Objects.requireNonNull(request, "无效请求");
String clientIp = IpUtil.getRemoteIP(request);
Set<String> paramKeys = request.getParameterMap().keySet();
boolean ready = paramKeys.contains(Constants.WECHAT_OPEN_ID);
if (!ready) {
return true;
} else if (Objects.isNull(user) || Objects.isNull(user.getId()) || StringUtils.isBlank(request.getParameter(Constants.WECHAT_OPEN_ID))) {
log.warn("微信关联失败,user:{}, request-Header:{}", user, JSON.toJSONString(getRequestHeaderMap(request)));
return false;
}
Long userId = user.getId();
String phoneNo = user.getPhoneNo();
try {
int rows = wechatService.relateUser(userId, phoneNo, request.getParameter(Constants.WECHAT_OPEN_ID));
return rows > 0;
} catch (Exception e) {
log.error("微信关联失败,user:{}, request-Header:{}", user, JSON.toJSONString(getRequestHeaderMap(request)), e);
}
return false;
}
}
Markdown is supported
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