redis客户端登陆:
redis-cli -h host -p port -a password
String类型的应用场景:
1)String通常用于保存单个字符串或者JSON格式的字符串数据
2)因为String类型通常是二进制安全的,因此你完全可以把一个图片内容当作字符串来进行存储
3)计数器,是常规的key-value缓存应用,常规计数,微博粉丝数
因为Incrby等指令本身就有原子操作的特性,所以我们完全可以利用redis的incr,incrby,decr,decrby等指令来实现原子计数的效果,假设说在某一种情况下3个客户端同时读取了num的值为1,那么这三个客户端同时针对num的值进行了+1的操作,那么最终这个num的值一定是5,不少网站都利用redis的这个特性来实现业务上的统计计数请求,不仅读写性能高,而且线程安全
Hash类型的应用场景:频繁对存储的对象进行增删改查
hash类型特别适用于存储对象数据,还常常用于存储一个对象或者是分布式session相比较于string类型而言,将一个对象存储到hash类型中要比存储在sring类型中要占用更少的内存空间,特别适用于存储对象的信息,还可以很方便的针对对象中的属性做增删改查,例如你要是用redis中的string类型来存储一个对象,那么就需要将JAVA中的Bean对象转化成一个JSON格式的字符串
key:product:user:1,value:对象的json格式字符串
上面的五个步骤不是一个原子操作,会产生线程安全问题
hash是最接近于关系数据库结构的数据类型,我们可以将数据库中的一套记录或者是一个对象转化成HashMap存储在redis中,把用户ID当作是查找的key,存储的value对象包括姓名,年龄,生日等信息,如果使用普通的key-value进行存储,主要是有下面两种存储方式:
1)第一种方式就是将用户ID作为查找的key,将其他信息封装成一个对象以序列化的方式来进行存储,这种方式的缺点是,增加了序列化和反序列化的开销,并且需要修改其中一项信息的时候,就需要将整个对象进行访问并且修改操作需要对并发进行保护,引入线程安全问题
2)第二种方法就是将用户信息对象有多少个成员就存放多少个key-value键值对,使用用户ID+对应属性的名称作为唯一标识来取得最终属性的值,虽然省去了序列化开销和并发问题,但是用户ID重复进行存储,内存空间浪费很大
所以redis中的hash很好地解决了这个问题,redis中的hash实际上时内部存储的value作为一个HashMap,并且直接存储了这个Map成员的接口
手机验证码的操作:
1)用户在客户端发送手机号,点击发送之后随机生成四位验证码,有效期为60s,输入验证码点击验证,返回成功或者失败
2)当后端收到用户发送过来的手机号,首先要生成key值,形式为key=phone:number:手机号码
3)生成key值之后,我们会首先查询这个key是否在redis中存在,如果不存在,并针对key进行赋值,并且设置过期时间是60s,如果当前的key已经在redis中存在了,那么系统就直接进行提示,验证码已经发送还在有效期内,请打开手机查看验证码
Controller @Slf4j public class UserController { public int GetRandomCode(){ int code=(int)(Math.random()*10000); return code; } @Autowired private StringRedisTemplate template; @RequestMapping("/GetCode") @ResponseBody public Object GetCode(@RequestParam("PhoneNumber") String PhoneNumber){ ValueOperations<String,String> options=template.opsForValue(); //1.先生成验证码 int RandomCode=GetRandomCode(); //2.生成key String key="phone:code:"+PhoneNumber; //3.在redis中进行查询 if(!template.hasKey(key)){ String value= String.valueOf(RandomCode); options.set(key,value,60, TimeUnit.SECONDS); log.info("短信验证码已经存储到redis里面,验证码是",RandomCode); return "验证码已经发送成功,请查看手机"; }else{ return "发送吗之前已经发送过了,请耐心等待"+options.getOperations().getExpire(key); } } }
@RequestMapping("/login") @ResponseBody public Object login(@RequestParam("PhoneNumber") String PhoneNumber) { ValueOperations<String,String> options=template.opsForValue(); //1.先生成key值 String key="phone:code:"+PhoneNumber; //2.查询key值在redis中是否存在 if(template.hasKey(key)){ //3.清空redis节省空间 template.delete(key); return"手机号和验证码校验成功,登陆成功"; } return "验证码错误或者手机号错误"; }
4)为了防止用户恶意攻击,我们做出,每一个IP地址在5分钟内最多发送三次验证码,如果在5min内频繁发送验证码超过三次,那么直接给出相应的信息提示,并且直接索死用户12小时