实例介绍
【实例简介】
【实例截图】
【核心代码】
【实例截图】
package com.pzhu.service; import com.pzhu.dao.SeckillMapper; import com.pzhu.dao.SeckillOrderMapper; import com.pzhu.dto.Exposer; import com.pzhu.dto.SeckillExecution; import com.pzhu.enums.SeckillStatEnum; import com.pzhu.exception.RepeatKillException; import com.pzhu.exception.SeckillCloseException; import com.pzhu.exception.SeckillException; import com.pzhu.pojo.Seckill; import com.pzhu.pojo.SeckillOrder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; import java.math.BigDecimal; import java.util.Date; import java.util.List; /** * @auther TyCoding * @date 2018/10/6 */ @Service public class SeckillServiceImpl implements SeckillService { private Logger logger = LoggerFactory.getLogger(this.getClass()); //设置盐值字符串,随便定义,用于混淆MD5值 private final String salt = "sjajaspu-i-2jrfm;sd"; //设置秒杀redis缓存的key private final String key = "seckill"; @Autowired private SeckillMapper seckillMapper; @Autowired private SeckillOrderMapper seckillOrderMapper; @Autowired private RedisTemplate redisTemplate; @Override public List<Seckill> findAll() { List<Seckill> seckillList = redisTemplate.boundHashOps("seckill").values(); if (seckillList == null || seckillList.size() == 0){ //说明缓存中没有秒杀列表数据 //查询数据库中秒杀列表数据,并将列表数据循环放入redis缓存中 seckillList = seckillMapper.findAll(); for (Seckill seckill : seckillList){ //将秒杀列表数据依次放入redis缓存中,key:秒杀表的ID值;value:秒杀商品数据 redisTemplate.boundHashOps(key).put(seckill.getSeckillId(), seckill); logger.info("findAll -> 从数据库中读取放入缓存中"); } }else{ logger.info("findAll -> 从缓存中读取"); } return seckillList; } @Override public Seckill findById(long seckillId) { return seckillMapper.findById(seckillId); } @Override public Exposer exportSeckillUrl(long seckillId) { Seckill seckill = (Seckill) redisTemplate.boundHashOps(key).get(seckillId); if (seckill == null) { //说明redis缓存中没有此key对应的value //查询数据库,并将数据放入缓存中 seckill = seckillMapper.findById(seckillId); if (seckill == null) { //说明没有查询到 return new Exposer(false, seckillId); } else { //查询到了,存入redis缓存中。 key:秒杀表的ID值; value:秒杀表数据 redisTemplate.boundHashOps(key).put(seckill.getSeckillId(), seckill); logger.info("RedisTemplate -> 从数据库中读取并放入缓存中"); } } else { logger.info("RedisTemplate -> 从缓存中读取"); } Date startTime = seckill.getStartTime(); Date endTime = seckill.getEndTime(); //获取系统时间 Date nowTime = new Date(); if (nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()) { return new Exposer(false, seckillId, nowTime.getTime(), startTime.getTime(), endTime.getTime()); } //转换特定字符串的过程,不可逆的算法 String md5 = getMD5(seckillId); return new Exposer(true, md5, seckillId); } //生成MD5值 private String getMD5(Long seckillId) { String base = seckillId "/" salt; String md5 = DigestUtils.md5DigestAsHex(base.getBytes()); return md5; } /** * 使用注解式事务方法的有优点:开发团队达成了一致约定,明确标注事务方法的编程风格 * 使用事务控制需要注意: * 1.保证事务方法的执行时间尽可能短,不要穿插其他网络操作PRC/HTTP请求(可以将这些请求剥离出来) * 2.不是所有的方法都需要事务控制,如只有一条修改的操作、只读操作等是不需要进行事务控制的 * <p> * Spring默认只对运行期异常进行事务的回滚操作,对于编译异常Spring是不进行回滚的,所以对于需要进行事务控制的方法尽可能将可能抛出的异常都转换成运行期异常 */ @Override @Transactional public SeckillExecution executeSeckill(long seckillId, BigDecimal money, long userPhone, String md5) throws SeckillException, RepeatKillException, SeckillCloseException { if (md5 == null || !md5.equals(getMD5(seckillId))) { throw new SeckillException("seckill data rewrite"); } //执行秒杀逻辑:1.减库存;2.储存秒杀订单 Date nowTime = new Date(); try { //记录秒杀订单信息 int insertCount = seckillOrderMapper.insertOrder(seckillId, money, userPhone); //唯一性:seckillId,userPhone,保证一个用户只能秒杀一件商品 if (insertCount <= 0) { //重复秒杀 throw new RepeatKillException("seckill repeated"); } else { //减库存 int updateCount = seckillMapper.reduceStock(seckillId, nowTime); if (updateCount <= 0) { //没有更新记录,秒杀结束 throw new SeckillCloseException("seckill is closed"); } else { //秒杀成功 SeckillOrder seckillOrder = seckillOrderMapper.findById(seckillId, userPhone); //更新缓存(更新库存数量) Seckill seckill = (Seckill) redisTemplate.boundHashOps(key).get(seckillId); seckill.setStockCount(seckill.getSeckillId() - 1); redisTemplate.boundHashOps(key).put(seckillId, seckill); return new SeckillExecution(seckillId, SeckillStatEnum.SUCCESS, seckillOrder); } } } catch (SeckillCloseException e) { throw e; } catch (RepeatKillException e) { throw e; } catch (Exception e) { logger.error(e.getMessage(), e); //所有编译期异常,转换为运行期异常 throw new SeckillException("seckill inner error:" e.getMessage()); } } }
【核心代码】
好例子网口号:伸出你的我的手 — 分享!
相关软件
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论