一、Redis
redis是一个速度非常快的非关系数据库,他可以存储键(key)与5种不同类型的值(value)之间的映射(mapping),可以将存储在内存的键值对数据持久化到硬盘,可以使用复制特性来扩展读性能,还可以使用客户端分片来扩展写性能。
二、Redis的数据结构
5种数据类型分别为STRING(字符串)、LIST(列表)、SET(集合)、HASH(散列)、ZSET(有序集合)。
2.1 字符串
字符串使用GET/SET/DEL方法
GET:获取存储在给定键中的值
SET:设置存储在键中的值
DEL:删除存储在给定键中的值
使用redis-cli做操作
2.2 列表
RPUSH:将给定值推入列表的右端
LRANGE:获取列表在给定范围上的所有值
LINDEX:获取列表在给定位置上的单个元素
LPOP:从列表的左端弹出一个值,并返回被弹出的值
2.3 集合
列表可以存储多个相同的字符串,而集合则通过使用散列表来保证自己存储的每个字符串都是不相同的
SADD:将给定元素添加到集合
SMEMBERS:返回集合包含的所有元素
SISMENBER:检查给定元素是否存在于集合中
SREM:如果给定的元素存在于集合中,那么移除这个元素
2.4 散列表
可以存储多个键值对之间的映射
HSET:关联给定的键值对
HGET:湖区指定散列表的值
HGETALL:获取散列包含的所有键值对
HDEL:如果给定键存在于散列里面,那么移除这个键
2.5 有序集合
有序集合和散列一样,都用于存储键值对。有序集合的键被称为成员,每个成员都是各不相同的;而有序集合的值则被称为分支,分值必须为浮点数。有序集合是redis里面唯一一个既可以根据成员访问元素,又可以根据分值以及分值的排列顺序来访问元素的结构。
ZADD:将一个带有给定分值的成员添加到有序集合里面
ZRANGE:根据元素在有序排列中所处的位置,从有序集合里面获取多个元素
ZRANGEBYSCORE:获取有序集合在给定分值范围内的所有元素
ZREM:如果给定成员存在于有序集合,那么移除这个成员
三、使用redis构建web应用
3.1 登录和cookie缓存
用来登录的cookie,有两种常见的方法可以将登录信息存储在cookie里面:一种是签名(signed)cookie,另一种是令牌(token)cookie
使用token来实现
验证和更新函数
package com.cf.logindemo;
import redis.clients.jedis.Jedis;
public class JedisCheck {
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost");
System.out.println("连接成功");
System.out.println("查看服务是否正在运行" + jedis.ping());
}
//检查令牌
public String checkToken(Jedis conn, String token){
//获取并返回令牌对应的用户
return conn.hget("login:",token);
}
//更新令牌
public void updateToken(Jedis conn, String user, String item, String token){
//获取当前时间戳
long timestamp = System.currentTimeMillis();
//维持令牌与已登录用户之间的映射
conn.hset("login:",token,user);
//纪录令牌最后一次出现的事件
conn.zadd("recent:",timestamp,token);
if(item != null){
//纪录浏览过的商品
conn.zadd("viewed:" + token , timestamp, item);
//移除旧纪录,只保留最近浏览的25个
conn.zremrangeByRank("viewed:" + token, 0, -26);
}
}
}
定期清理旧的会话数据
package com.cf.logindemo;
import redis.clients.jedis.Jedis;
import java.util.ArrayList;
import java.util.Set;
public class CleanSessions extends Thread{
private Boolean quit = false;
private Long limit = 10000L;
private Jedis conn;
public void quit(){
quit = true;
}
@Override
public void run() {
while(!quit){
//找出目前已有令牌的数量
long size = conn.zcard("recent:");
//如果令牌数量未超过限制,进行休眠在重新开始检查
if(size < limit){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
//获取需要移除的令牌ID,每次最多清理100个
Long end_index = Math.min(size - limit, 100L);
Set<String> tokens = conn.zrange("recent:", 0, end_index - 1);
ArrayList<String> sessionKeys = new ArrayList<String>();
for (String token : tokens) { //为需要移除的构键名
sessionKeys.add("viewed:" + token);
}
//移除最旧 的令牌
conn.del(sessionKeys.toArray(new String[sessionKeys.size()]));
conn.hdel("login:",tokens.toArray(new String[tokens.size()]));
conn.zrem("recent:",tokens.toArray(new String[tokens.size()]));
}
}
}
3,2 使用redis实现购物车
使用redis存储购物车,使用散列存储商品ID和数量之间的映射
package com.cf.cartdemo;
import redis.clients.jedis.Jedis;
public class CartDemo {
//添加商品到购物车
public void addToCart(Jedis conn,String item,int count,String session){
if(count <= 0){
//从购物车里移除指定的商品
conn.hdel("cart:"+session,item);
}else{
//将指定商品添加到购物车
conn.hset("cart:"+session,item,String.valueOf(count));
}
}
}
更新清理代码,清理时同时清除对应用户的购物车
参考:redis实战