高并发秒杀项目——页面优化
页面缓存+URL缓存+对象缓存
页面缓存
改造GoodsController中的方法,加入ThymeleafViewResolver注解
@RequestMapping(value = "/to_list",produces ="text/html" )
@ResponseBody
public String list(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user) {
model.addAttribute("user", user);
//查询商品列表,包括商品和秒杀商品
List<GoodsVo> goodsList = goodsService.listGoodsVo();
model.addAttribute("goodsList", goodsList);
// return "goods_list";
// 取缓存
String html = redisService.get(GoodsKey.getGoodsList,"",String.class);
if (!StringUtils.isEmpty(html)){
return html;
}
//手动渲染
SpringWebContext ctx = new SpringWebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap(), applicationContext);
html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);
if (!StringUtils.isEmpty(html)){
redisService.set(GoodsKey.getGoodsList, "", html);
}
return html;
}
GoodsKey :作为页面缓存的缓存Key的前缀,缓存有效时间,一般设置为1分钟
public class GoodsKey extends BasePrefix{
public GoodsKey(int expireSeconds, String prefix) {
super(expireSeconds, prefix);
}
public static GoodsKey getGoodsList = new GoodsKey(60, "gl");
public static GoodsKey getGoodsDetail = new GoodsKey(60, "gd");
}
URL缓存
相当于页面缓存,针对不同的详情页显示不同缓存页面,对不同的url进行缓存
@RequestMapping(value = "/to_detail/{goodsId}",produces = "text/html")
@ResponseBody
public String detail(HttpServletRequest request, HttpServletResponse response, Model model, MiaoshaUser user, @PathVariable("goodsId") long goodsId) {
model.addAttribute("user", user);
// 取缓存
String html = redisService.get(GoodsKey.getGoodsList,"",String.class);
if (!StringUtils.isEmpty(html)){
return html;
}
GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
model.addAttribute("goods", goods);
//转化为毫秒
long startAt = goods.getStartDate().getTime();
long endAt = goods.getEndDate().getTime();
long now = System.currentTimeMillis();
int miaoshaStatus = 0; //秒杀状态
int remainSeconds = 0; //距离开始秒杀还有多少秒
if (now < startAt){ //秒杀还没开始,倒计时
miaoshaStatus = 0;
remainSeconds = (int)((startAt - now)/1000);
}else if (now > endAt){ //秒杀结束
miaoshaStatus = 2;
remainSeconds = -1;
}else { //秒杀中
miaoshaStatus = 1;
remainSeconds = 0;
}
model.addAttribute("miaoshaStatus", miaoshaStatus);
model.addAttribute("remainSeconds", remainSeconds);
SpringWebContext ctx = new SpringWebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap(), applicationContext);
html = thymeleafViewResolver.getTemplateEngine().process("goods_detail", ctx);
if (!StringUtils.isEmpty(html)){
redisService.set(GoodsKey.getGoodsDetail, ""+goodsId, html);
}
return html;
}
对象缓存
MiaoshaUserService里面增加getById方法,先去取缓存,如果缓存中拿不到,那么就去取数据库,然后再设置到缓存中去
public MiaoshaUser getById(long id){
//取缓存
MiaoshaUser user = redisService.get(MiaoshaUserKey.getById, ""+id, MiaoshaUser.class);
if (user != null){
return user;
}
//取数据库
user = miaoshaUserDao.getById(id);
if (user != null){
redisService.set(MiaoshaUserKey.getById, ""+id, user);
}
return user;
// return miaoshaUserDao.getById(id);
}
更新用户密码:更新数据库与缓存,一定保证数据一致性,修改token关联的对象以及id关联的对象,先更新数据库后删除缓存,不能直接删除token,删除之后就不能登录了,再将token以及对应的用户信息一起再写回缓存里面去。
public boolean updatePassword(String token, long id, String formPass){
//取user对象
MiaoshaUser miaoshaUser = getById(id);
if (miaoshaUser == null){
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//更新数据库
MiaoshaUser toBeUpdate = new MiaoshaUser();
toBeUpdate.setId(id);
toBeUpdate.setPassword(MD5Util.formPassToDBPass(formPass, miaoshaUser.getSalt()));
miaoshaUserDao.update(toBeUpdate);
//处理缓存
redisService.delete(MiaoshaUserKey.getById, ""+id);
miaoshaUser.setPassword(toBeUpdate.getPassword());
redisService.set(MiaoshaUserKey.token, token, miaoshaUser);//更新token
return true;
}
RedisService里面的delete方法
public Boolean delete(KeyPrefix prefix, String key){
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String realPrefix = prefix.getPrefix() + key;
long ret = jedis.del(realPrefix);
return ret > 0;
}finally {
returnToPool(jedis);
}
}
MiaoshaUserDao 中的Update方法
@Update("update miaosha_user set password = #{password} where id = #{id}")
public void update(MiaoshaUser toBeUpdate);