.setex可覆盖 原子性
setex不可覆盖
单点登录
1.查到校验成功的用户后将用户sessionId存入cookie保存到浏览器Cookie ck = new Cookie(COOKIE_NAME,sessionId)
2.将用户session存入redis jedis.setex(sessionId,exTime,user.toString());可覆盖旧key得值
3.查用户先从cookie中获取sessionId再从redis获取用户session信息,退出则先删除cookie再删除redis
4.在过滤器中从cookie中获取sessionId重置redis中用户session信息的有效时长 jedis.expire(sessionId,exTime);
code:
package com.mmall.controller.portal;
import com.mmall.common.Const;
import com.mmall.common.ResponseCode;
import com.mmall.common.ServerResponse;
import com.mmall.pojo.User;
import com.mmall.service.IUserService;
import com.mmall.util.CookieUtil;
import com.mmall.util.JsonUtil;
import com.mmall.util.RedisShardedPoolUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Created by geely
*/
@Controller
@RequestMapping("/user/")
public class UserController {
@Autowired
private IUserService iUserService;
/**
* 用户登录
* @param username
* @param password
* @param session
* @return
*/
@RequestMapping(value = "login.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse login(String username, String password, HttpSession session, HttpServletResponse httpServletResponse){
ServerResponse response = iUserService.login(username,password);
if(response.isSuccess()){
// session.setAttribute(Const.CURRENT_USER,response.getData());
CookieUtil.writeLoginToken(httpServletResponse,session.getId());
RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()),Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
}
return response;
}
@RequestMapping(value = "logout.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse logout(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
CookieUtil.delLoginToken(httpServletRequest,httpServletResponse);
RedisShardedPoolUtil.del(loginToken);
// session.removeAttribute(Const.CURRENT_USER);
return ServerResponse.createBySuccess();
}
@RequestMapping(value = "register.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse register(User user){
return iUserService.register(user);
}
@RequestMapping(value = "check_valid.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse checkValid(String str,String type){
return iUserService.checkValid(str,type);
}
@RequestMapping(value = "get_user_info.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse getUserInfo(HttpServletRequest httpServletRequest){
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
if(StringUtils.isEmpty(loginToken)){
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
}
String userJsonStr = RedisShardedPoolUtil.get(loginToken);
User user = JsonUtil.string2Obj(userJsonStr,User.class);
if(user != null){
return ServerResponse.createBySuccess(user);
}
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
}
@RequestMapping(value = "forget_get_question.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse forgetGetQuestion(String username){
return iUserService.selectQuestion(username);
}
@RequestMapping(value = "forget_check_answer.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse forgetCheckAnswer(String username,String question,String answer){
return iUserService.checkAnswer(username,question,answer);
}
@RequestMapping(value = "forget_reset_password.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse forgetRestPassword(String username,String passwordNew,String forgetToken){
return iUserService.forgetResetPassword(username,passwordNew,forgetToken);
}
@RequestMapping(value = "reset_password.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse resetPassword(HttpServletRequest httpServletRequest,String passwordOld,String passwordNew){
// User user = (User)session.getAttribute(Const.CURRENT_USER);
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
if(StringUtils.isEmpty(loginToken)){
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
}
String userJsonStr = RedisShardedPoolUtil.get(loginToken);
User user = JsonUtil.string2Obj(userJsonStr,User.class);
if(user == null){
return ServerResponse.createByErrorMessage("用户未登录");
}
return iUserService.resetPassword(passwordOld,passwordNew,user);
}
@RequestMapping(value = "update_information.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse update_information(HttpServletRequest httpServletRequest,User user){
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
if(StringUtils.isEmpty(loginToken)){
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
}
String userJsonStr = RedisShardedPoolUtil.get(loginToken);
User currentUser = JsonUtil.string2Obj(userJsonStr,User.class);
if(currentUser == null){
return ServerResponse.createByErrorMessage("用户未登录");
}
user.setId(currentUser.getId());
user.setUsername(currentUser.getUsername());
ServerResponse response = iUserService.updateInformation(user);
if(response.isSuccess()){
response.getData().setUsername(currentUser.getUsername());
RedisShardedPoolUtil.setEx(loginToken, JsonUtil.obj2String(response.getData()),Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
}
return response;
}
@RequestMapping(value = "get_information.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse get_information(HttpServletRequest httpServletRequest){
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
if(StringUtils.isEmpty(loginToken)){
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
}
String userJsonStr = RedisShardedPoolUtil.get(loginToken);
User currentUser = JsonUtil.string2Obj(userJsonStr,User.class);
if(currentUser == null){
return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),"未登录,需要强制登录status=10");
}
return iUserService.getInformation(currentUser.getId());
}
}
===============================================================
分布式锁
jedis.setnx(key,value)不可覆盖
设置成功,返回 1 。 设置失败,返回 0 。
先jedis.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,System.currentTimeMillis()+lockTimeout)设置锁,如果返回1成功获取到锁,则调用业务代码,在业务代码开头使用jedis.expire(key,exTime);防止死锁,业务代码结束后使用jedis.del(key)删除锁;如果没有获取到锁,通过当前时间与System.currentTimeMillis()+lockTimeout比较大小
redission RLock 可重入锁 rlock.tryLock(0,50, TimeUnit.SECONDS)
RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
boolean getLock = false;
if(getLock = lock.tryLock(0,50, TimeUnit.SECONDS)){
log.info("Redisson获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
// iOrderService.closeOrder(hour);
}else{
log.info("Redisson没有获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
}
code:
package com.mmall.task;
import com.mmall.common.Const;
import com.mmall.common.RedissonManager;
import com.mmall.service.IOrderService;
import com.mmall.util.PropertiesUtil;
import com.mmall.util.RedisShardedPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;
/**
* Created by geely
*/
@Component
@Slf4j
public class CloseOrderTask {
@Autowired
private IOrderService iOrderService;
@Autowired
private RedissonManager redissonManager;
@PreDestroy
public void delLock(){
RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
// @Scheduled(cron="0 */1 * * * ?")//每1分钟(每个1分钟的整数倍)
public void closeOrderTaskV1(){
log.info("关闭订单定时任务启动");
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
// iOrderService.closeOrder(hour);
log.info("关闭订单定时任务结束");
}
// @Scheduled(cron="0 */1 * * * ?")
public void closeOrderTaskV2(){
log.info("关闭订单定时任务启动");
long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
if(setnxResult != null && setnxResult.intValue() == 1){
//如果返回值是1,代表设置成功,获取锁
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}else{
log.info("没有获得分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
log.info("关闭订单定时任务结束");
}
@Scheduled(cron="0 */1 * * * ?")
public void closeOrderTaskV3(){
log.info("关闭订单定时任务启动");
long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
if(setnxResult != null && setnxResult.intValue() == 1){
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}else{
//未获取到锁,继续判断,判断时间戳,看是否可以重置并获取到锁
String lockValueStr = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
if(lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)){
String getSetResult = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
//再次用当前时间戳getset。
//返回给定的key的旧值,->旧值判断,是否可以获取锁
//当key没有旧值时,即key不存在时,返回nil ->获取锁
//这里我们set了一个新的value值,获取旧的值。
if(getSetResult == null || (getSetResult != null && StringUtils.equals(lockValueStr,getSetResult))){
//真正获取到锁
closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}else{
log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
}else{
log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
}
}
log.info("关闭订单定时任务结束");
}
// @Scheduled(cron="0 */1 * * * ?")
public void closeOrderTaskV4(){
RLock lock = redissonManager.getRedisson().getLock(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
boolean getLock = false;
try {
if(getLock = lock.tryLock(0,50, TimeUnit.SECONDS)){
log.info("Redisson获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
// iOrderService.closeOrder(hour);
}else{
log.info("Redisson没有获取到分布式锁:{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
}
} catch (InterruptedException e) {
log.error("Redisson分布式锁获取异常",e);
} finally {
if(!getLock){
return;
}
lock.unlock();
log.info("Redisson分布式锁释放锁");
}
}
private void closeOrder(String lockName){
RedisShardedPoolUtil.expire(lockName,5);//有效期50秒,防止死锁
log.info("获取{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
iOrderService.closeOrder(hour);
RedisShardedPoolUtil.del(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
log.info("释放{},ThreadName:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,Thread.currentThread().getName());
log.info("===============================");
}
}