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中添加)

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

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)));
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • NOSQL类型简介键值对:会使用到一个哈希表,表中有一个特定的键和一个指针指向特定的数据,如redis,volde...
    MicoCube阅读 3,958评论 2 27
  • “××的父亲去世了,昨晚的事。”一早到办公室,看到师兄发来的消息,我大吃一惊,“怎么会?”我还以为他是在骗我,可想...
    SHE林阅读 169评论 0 0
  • 当有人与你发出不合谐的音符的时候;当有人与你不在一个频道欣赏节目的时候;当有人不能一路与你一起看风景的时候,不能也...
    lucky9125阅读 473评论 0 0
  • 来到丽江.悠闲安静.
    時光流轉阅读 153评论 0 0