AskMe项目 Redis学习 赞踩实现

什么是Redis

Key-Value型的数据库,和Mysql的二维表不一样,性能很好,数据存在内存中,支持通用数据结构,如队列,集合,哈希队列等

  1. 官网
  2. github安装地址
  3. 官网命令
  4. 书籍推荐:《Redis设计与实现》

基本命令

  • set key value key为你想添加的键值,value为你想添加的键值对应的值,value可以为任何类型的数据结构
  • get key找到key对应的value值
  • select num选择一个数据库(默认为16个数据库,select 9表示选择第9个数据库)
  • keys 正则表达式 找到满足正则表达式的所有键值

Redis config

  • 打开安装文件夹中的redis.windows.conf,以下几行表示900秒中有一个key值发生变化,就会进行一次备份,300秒中有10个key值发生变化,就会进行一次备份,最后一行同理。因为Redis是内存型的数据库,所以需要一个机制来让改变的数据同步到文件中
save 900 1
save 300 10
save 60 10000
  • 两种存储方式
    RDB:某一时刻数据库当前状态,把最终结果保存起来,适合修改次数比较多的情况
    AOF:不记最终结果,记录所有执行的命令(通过再执行一遍命令,来得到数据库当前状态),可以避免丢失数据

使用Jedis连接Redis

github地址
安装方法
1. 项目中添加依赖(在pom.xml中添加)

        
            redis.clients
            jedis
            2.9.0
        

2. 代码中使用方法

Jedis jd=new Jedis("redis://localhost:6379/6");
//连接第6个数据库(安装时默认端口为6379)
jd.flushDB(); //将该数据库中的数据清除,flushAll是将所有数据都清除
jd.set("hello","fsa"); //添加key value对
print(1,jd.get("hello")); //jd.get获取key值对应的value

3.List的使用
双向列表,适用于最新列表,关注列表

String name="list";
jd.del(name);
jd.lpushx(name,"ifexists");//如果name这个key存在才Push
print(0,jd.lrange(name,0,jd.llen(name)));//lrange得到下标从start到end的name中元素list
for(int i=0;i<10;i++)
{
     jd.lpush(name,"a"+String.valueOf(i),"b"+String.valueOf(i));
     //从左边压入,相当于栈,先进来的下标大
}
for(int i=11;i<20;i++)
    jd.rpush(name,"a"+String.valueOf(i));
    //从右边压入,相当于队列,先进来的下标小
print(1,jd.lrange(name,0,jd.llen(name)));//llen获取列表长度
print(2,jd.lindex(name,6));//获取下标为6的元素
jd.linsert(name, BinaryClient.LIST_POSITION.AFTER,"a8","hello");
jd.linsert(name, BinaryClient.LIST_POSITION.AFTER,"a8","hello");
//在“a8”元素后面插入两个hello,执行了两次
jd.linsert(name, BinaryClient.LIST_POSITION.BEFORE,"a8","you");
//在“a8”元素前面插入一个you
print(5,jd.lpop(name));//pop掉第一个元素,并返回第一个元素
jd.lrem(name,2,"hello");//删除两个hello
jd.lset(name,0,"me");//把下标为0的设为me
jd.ltrim(name,0,9);//裁剪,只留下下标0-9的元素

4.Hash的使用

String hset="hset";
jd.hset(hset,"name","ERIKA");//在hset中设置key-value对,name对应为ERIKA
jd.hset(hset,"age","21");
jd.hset(hset,"school","fdu");
print(1,jd.hgetAll(hset));//得到所有hset中的key-value对,结果类似dict
print(2,jd.hget(hset,"name"));//得到hset中name这个key对应的value
print(3,jd.hexists(hset,"family"));//判断hset中是否有family这个key,返回boolean
print(5,jd.hkeys(hset));//得到hset所有的keys的集合
print(6,jd.hlen(hset));//返回hset的长度
print(7,jd.hdel(hset,"school"));//删除hset的school这个key的键值对
jd.hsetnx(hset,"name","hello");//如果不存在就添加,存在则不再修改,可以防止篡改
jd.hsetnx(hset,"school","fduu");

5.Set的使用

String name="set";
String name2="set2";
for(int i=0;i<10;i++)
{
    jd.sadd(name,String.valueOf(i));//在集合name中添加值
    jd.sadd(name2,String.valueOf(i*i));
}
print(1,jd.scard(name));//返回name的长度
jd.srem(name,"4");//删除4这个元素
print(2,jd.smembers(name));//返回name中所有元素的集合
jd.smove(name2,name,"16");//把name2中的16移到name中,name2中删除,name中添加
print(5,jd.sismember(name,"9"));//判断9是否为name集合中的元素
print(7,jd.sunion(name,name2));//求并
print(8,jd.sinter(name,name2));//求交
print(9,jd.sdiff(name2,name));//求不同的元素

6.Sorted List的使用

String name="sortedlist";
jd.zadd(name,100,"Erika");//有序列表中添加名字和score的对应值
jd.zadd(name,80,"Lily");
jd.zadd(name,60,"Ben");
jd.zadd(name,40,"Jim");
print(1,jd.zcard(name));//返回list长度
print(2,jd.zcount(name,60,100));//计算score为60-100的人数
print(3,jd.zrange(name,0,2));//返回score从小到大第0-2名的名字
print(4,jd.zrangeByScore(name,60,100));//成绩从小到大60-100分的名字
print(5,jd.zrevrangeByScore(name,100,80));//成绩从大到小60-100分的名字
print(6,jd.zscore(name,"Erika"));//返回名叫Erika的成绩
jd.zincrby(name,5,"Lily");//给Lily的成绩加5分
print(7,jd.zrevrange(name,0,jd.zcard(name)));//输出所有成绩从大到小排序的人名
for(Tuple tuple:jd.zrevrangeByScoreWithScores(name,100,60))
{
    print(8,tuple.getElement()+":"+String.valueOf(tuple.getScore()));
    //输出  名字:成绩
}
print(9,jd.zrank(name,"Lily"));//得到Lily从小到大的排名
print(10,jd.zrevrank(name,"Lily"));//得到Lily从大到小的排名

String s="zset";
jd.zadd(s,1,"a");
jd.zadd(s,1,"g");
jd.zadd(s,1,"b");
jd.zadd(s,1,"d");

print(11,jd.zlexcount(s,"-","+"));//计算从负无穷到正无穷的个数
print(12,jd.zlexcount(s,"[b","[c"));//计算从b-c(左右都包)的个数,按照字典序,lex只有在score一样时有效
print(13,jd.zlexcount(s,"(b","[g"));//左不包右包
jd.zremrangeByLex(s,"(b","[g");//删除这个区间内的所有元素

7.链接池的使用
默认8个线程可以连接,从池中取出连接后如果不close掉线程8个之后的进不来,所以用好一定要关掉

        JedisPool pool=new JedisPool();
        for(int i=0;i<10;i++)
        {
            Jedis j=pool.getResource();
           print(i,j.keys("*"));
            print(i,j.get("pv"));
            j.close();
        }

使用这种方式,默认getresource是第0号数据库,使用下面的方法可以设定为第6号数据库

JedisPool pool=new JedisPool("redis://localhost:6379/6");

8.Json序列化实现对象的缓存和取出

        User user=new User();
        user.setPassword("1");
        user.setHeadUrl("fd.png");
        user.setSalt("fdsa");
        user.setName("hello");
        user.setId(10);
        //转换成Json字符串
        jd.set("user1",JSONObject.toJSONString(user));
        
        //取出时使用parseObject来将json字符串回到class
        User user2= JSON.parseObject(jd.get("user1"),User.class);
        print(10,user2.getName());

集合实现赞踩功能

1.建立JedisService来实现数据库连接和具体操作的接口(其他功能又需要使用Redis数据库时,可以重复使用)

@Service
public class JedisService implements InitializingBean{
    private static final Logger logger= LoggerFactory.getLogger(JedisService.class) ;
    private JedisPool pool;

    public long addkeyvalue(String key,String value)
    {
        Jedis j=null;
        try
        {
            j=pool.getResource();
            return j.sadd(key,value);
        }
        catch (Exception e)
        {
            logger.error("redis添加失败"+e);
        }
        finally {
            if(j!=null)
                j.close();
        }
        return 0;

    }

    public long delvalue(String key,String value)
    {
        Jedis j=null;
        try
        {
            j=pool.getResource();
            return j.srem(key,value);
        }
        catch (Exception e)
        {
            logger.error("删除失败"+e);
        }
        finally {
            if(j!=null)
                j.close();
        }
        return 0;
    }
    public boolean ismember(String key,String value)
    {
        Jedis j=null;
        try
        {
            j=pool.getResource();
            return j.sismember(key,value);
        }
        catch (Exception e)
        {
            logger.error("获取是否为成员失败"+e);
        }
        finally {
            if(j!=null)
                j.close();
        }
        return false;
    }

    public long getcount(String key)
    {
        Jedis j=null;
        try
        {
            j=pool.getResource();
            return j.scard(key);
        }
        catch(Exception e)
        {
            logger.error("获取总数失败"+e);
        }
        finally {
            if(j!=null)
                j.close();
        }
        return 0;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        pool=new JedisPool("redis://localhost:6379/6");
    }
}

2. 建立LikeService来实现实际Like or DisLike的数据更新(多个页面位置需要实现赞踩功能时可以重复使用)

@Service
public class LikeService {
    @Autowired
    JedisService j;

    public long addLike(int entity_type,int entity_id,int user_id)
    {
        String key= new RedisKeyUtil().getLikeKey(entity_type,entity_id);
        return j.addkeyvalue(key,String.valueOf(user_id));
    }
    public long addDislike(int entity_type,int entity_id,int user_id)
    {
        String key=new RedisKeyUtil().getDislikeKey(entity_type,entity_id);
        return j.addkeyvalue(key,String.valueOf(user_id));
    }

    public int isLikeorDislike(int entity_type,int entity_id,int user_id)
    {
        String key=new RedisKeyUtil().getLikeKey(entity_type,entity_id);
        if(j.ismember(key,String.valueOf(user_id)))
            return 1;
        key=new RedisKeyUtil().getDislikeKey(entity_type,entity_id);
        if(j.ismember(key,String.valueOf(user_id)))
            return 2;
        return 0;
    }

    public long getCountLike(int entity_type,int entity_id)
    {
        String key=new RedisKeyUtil().getLikeKey(entity_type,entity_id);
        return j.getcount(key);
    }
    public long dellike(int entity_type,int entity_id,int user_id)
    {
        String key=new RedisKeyUtil().getLikeKey(entity_type,entity_id);
        return j.delvalue(key,String.valueOf(user_id));
    }

    public long delDislike(int entity_type,int entity_id,int user_id)
    {
        String key=new RedisKeyUtil().getDislikeKey(entity_type,entity_id);
        return j.delvalue(key,String.valueOf(user_id));
    }

}

3. 建立RedisKeyUtil工具,来根据实际的功能和ID等参数,实现生成Keys的功能,以防止出现Key值重复而导致覆盖的问题

    public class RedisKeyUtil {
    private int entity_type;
    private int entity_id;
    public String getLikeKey(int entype,int id)
    {
        return "Like-"+String.valueOf(entype)+"-"+String.valueOf(id);
    }
    public String getDislikeKey(int entype,int id)
    {
        return "Dislike-"+String.valueOf(entype)+"-"+String.valueOf(id);
    }
}

4.Controller中添加相关路径和方法

@Controller
public class LikeController {
    @Autowired
    HostHolder host;

    @Autowired
    LikeService like;

    @RequestMapping(path={"/like"},method={RequestMethod.POST})
    @ResponseBody
    public String likeit(@RequestParam("commentId")int entity_id)
    {
        User user=host.getuser();
        if(user==null)
            return WendaUtil.generatejson(999);
        if(like.isLikeorDislike(EntityType.ENTITY_COMMENT,entity_id,user.getId())==2)
        {
            like.delDislike(EntityType.ENTITY_COMMENT,entity_id,user.getId());
        }
        like.addLike(EntityType.ENTITY_COMMENT,entity_id,user.getId());
        return WendaUtil.generatejson(0,String.valueOf(like.getCountLike(EntityType.ENTITY_COMMENT,entity_id)));
    }
    @RequestMapping(path={"/dislike"},method={RequestMethod.POST})
    @ResponseBody
    public String dislikeit(@RequestParam("commentId")int entity_id)
    {
        User user=host.getuser();
        if(user==null)
            return WendaUtil.generatejson(999);
        if(like.isLikeorDislike(EntityType.ENTITY_COMMENT,entity_id,user.getId())==1)
        {
            like.dellike(EntityType.ENTITY_COMMENT,entity_id,user.getId());
        }
        like.addDislike(EntityType.ENTITY_COMMENT,entity_id,user.getId());
        return WendaUtil.generatejson(0,String.valueOf(like.getCountLike(EntityType.ENTITY_COMMENT,entity_id)));
    }
}

你可能感兴趣的:(AskMe项目 Redis学习 赞踩实现)