一、 Redis简介

     Redis是用C语言编写的开源软件,可以运行在Linux上,目前不支持Windows。Redis通常会被用于缓存、数据持久化、消息队列,Redis避免了服务器挂掉后,内存数据丢失的问题。Redis支持5种数据结构: strings, hashes, lists, sets, sorted sets,而且对于这些数据结构上的操作都是原子性的,这意味着操作这些集合是线程安全的;Redis首先是把数据集放在内存上的,可以设置每隔一段儿时间持久化数据到硬盘,如果工程中仅仅需要Redis做缓存,持久化也是可以被禁止的;Redis支持像Mysql一样的主从同步,主服务器上的数据可以同步到N个从服务器上,可以读写分离。

     大多数编程语言都能使用Redis,C、C++、Java、C#、Python都能通过相应的API通过Redis服务端的IP和端口使用Redis服务。在下面的章节中主要以Java为例介绍Redis数据结构上的简单操作。

 

二、Redis支持的数据结构以及简单操作

1. String

  在String类数据结构上,Redis和Memcached一致,都支持Key-Value的数据存储(一个Key对应一个Value,相当于Java中的HashMap),支持给一个Key设定一个value,支持在特定Key下的Value后添加字符串、删除特定Key等操作、对相应Key的数字value进行原子的加减操作。

 

public class RedisClient {
    private static final String HOST="192.168.146.129";
    private static final int PORT=6379;
    
    private  final Jedis jedis=new Jedis(HOST,PORT);
    
    /**
     * 测试 Redis做Key-Value存取
     */
    @Test
    public void testKeyValue(){
        jedis.set("name", "boruoyihao");
        System.out.println("Get name from redis:"+jedis.get("name")); 
        System.out.println("Is exist in redis:"+jedis.exists("name"));
        jedis.append("name", ",Hello"); //相同Key下添加
        System.out.println("Get name from redis:"+jedis.get("name"));
        
        jedis.del("name");  //delete the Key 
        System.out.println("Get name from redis:"+jedis.get("name"));
        
        //相当于jedis.set("name","boreyihao");
        //jedis.set("age",26);
        jedis.mset("name","boreyihao","age","26");
        System.out.println(jedis.get("name")+"=="+jedis.get("age")); 
        
        //设置name有效时间为2S
        jedis.setex("name", 2, "boruo");
        System.out.println("Get name from redis:"+jedis.get("name"));
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //name时间超时,取出数据为null
        System.out.println("Get name from redis:"+jedis.get("name"));
        
        //原子递增操作
        jedis.set("age", "26");
        jedis.incr("age");
        System.out.println("Get age from redis:"+jedis.get("age"));
        jedis.decrBy("age", 3);
        System.out.println("Get age from redis:"+jedis.get("age"));
    }

}

2. hashes

     Redis的Hash可以以一个键值存入一个Map对象,可以获取整个Map对象,也可以获取Map对象的key集合或者Value集合,也可以获取指定Field的Value,也可以对指定Field的整数值执行加减操作。Redis可以存对象的属性以及属性值,但是memcached存对象 只能转化为字符串,如果要修改对象的值,只能把字符串取出来转化为对象,然后修改对象,再转化为字符串存回memcached,开销还是很大的,这是Redis的优势所在。

    @Test
    public void testHash(){
        //test hashmap
        Map<String,String>m=new HashMap<String,String>();
        m.put("name", "Tom");
        m.put("major", "Software");
        m.put("age", "43");
        jedis.hmset("m", m);
        List<String> name=jedis.hmget("m", "name"); // m为key,name为m的key,返回的是List
        System.out.println(name);
        System.out.println("Get Hash Values="+jedis.hvals("m"));
        
        Iterator<String> it=jedis.hkeys("m").iterator();
        while(it.hasNext()){
            String key=it.next();
            System.out.println(key+":"+jedis.hmget("m", key));
        }
        System.out.println("Get keys from redis:"+jedis.hkeys("m"));
        System.out.println("Get Values from redis:"+jedis.hvals("m"));
        
        Map<String,String>map=jedis.hgetAll("m");
        System.out.println("Get map from Redis:"+map);
        
        
        //Test hashset
        System.out.println("---test hash set");
        jedis.hset("s", "name", "Jack");
        jedis.hset("s", "age", "25");
        System.out.println(jedis.hexists("s", "name"));
        System.out.println(jedis.hget("s", "name"));
        System.out.println(jedis.hgetAll("s"));
        Map<String,String>smap=jedis.hgetAll("s");
        System.out.println(smap);
        
        System.out.println(jedis.hdel("s", "name"));  //清除name属性
        System.out.println(jedis.hincrBy("s", "age", 3));
        System.out.println("after incr:"+jedis.hgetAll("s"));
    }

 

3. lists

     List是一个双向链表,原因是Redis支持在这个链表的两端插入和弹出操作,所以Redis的List除了是双向链表外,也可以用于队列,也可以用于栈。

    @Test
    public void testList(){
        System.out.println("test List");
        jedis.del("task");
        jedis.rpush("task", "do homework");//在链表尾部添加
        jedis.rpush("task", "clean housr");
        jedis.lpush("task", "rest");//在链表头部添加
        jedis.lpush("task", "watch tv");
        System.out.println("length:"+jedis.llen("task"));
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1)); //-1表示到最后,表示取出从头到尾的数据
        System.out.println("target Index:"+jedis.lindex("task", 2));
        System.out.println(jedis.lpop("task"));//取出头部数据
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1));
        System.out.println(jedis.rpop("task"));//取出尾部数据
        System.out.println("Get all List:"+jedis.lrange("task", 0, -1));
        
    }

 

 

 

4. sets

     Redis的Set相当于Java的hashset,元素排列有序,更强的是它可以很方便的求两个集合的并、交、差集。

 

    @Test
    public void testSet(){
        System.out.println("test Set");
        jedis.del("s1");
        jedis.sadd("s1", "4","1","3","20");  //有序
        System.out.println("Get all s1:"+jedis.smembers("s1")); //有序的
        System.out.println("Get no s1:"+jedis.scard("s1"));
        
        jedis.sadd("s2", "4","11","13","34","3","20");
        System.out.println("Get all s2:"+jedis.smembers("s2")); //有序的
        System.out.println("Get no s2:"+jedis.scard("s2"));
        
        System.out.println(jedis.sinter("s1","s2"));//交集
        System.out.println(jedis.sunion("s1","s2")); //并集
        System.out.println(jedis.sdiff("s1","s2"));//差集
    }

 

 

 

5. sorted sets

     Redis的Sorted Sets 是对Set补充,可以根据权值进行排序,同样不允许重复。

    @Test
    public void testSortedSet(){
        System.out.println("testSortedset");
        jedis.zadd("ss", 12, "Tom"); //中间为权值,根据权值排序
        jedis.zadd("ss", 1, "Jack");
        jedis.zadd("ss", 20, "David");
        jedis.zadd("ss", 3, "Jim");
        System.out.println("sortedset length:"+jedis.zcard("ss")); //获取元素个数
        System.out.println("sorted set:"+jedis.zrange("ss", 0, -1));  //输出按权值排列
        
        jedis.zadd("ss1", 1, "Tom"); //中间为权值
        jedis.zadd("ss1", 3, "Jimmy");
        jedis.zadd("ss1", 2, "Alex");
        jedis.zadd("ss1", 5, "Jim");
        
        System.out.println("sortedset length:"+jedis.zcard("ss1")); //获取元素个数
        System.out.println("sorted set:"+jedis.zrange("ss1", 0, -1));  //输出按权值排列
        
        System.out.println(jedis.zscore("ss1", "Tom")); //获取Tom的排序权值
        
    }

 三、Redis应用

结合以上对Redis数据结构的介绍,Redis在服务端开发技术上,简单来说是可以做缓存,并可以做数据持久化,以下几方面是菜鸟的理解。

1. 消息队列

在本文第二部分介绍了Redis有双向链表List,并且支持双进双出,所以可以用Redis做消息队列,比如通知的消息、任务、邮件等都可以存储在消息队列,然后另一端可以通过Redis能支持的大部分语言消费队列里的数据,这样便于系统模块之间的解耦,降低模块之间的依赖性;并且把同步消息处理方式转化为异步处理,不会造成队列阻塞。微博的用户微博列表应该是用Redis做的缓存。

 

2. 列出某项列表最新几条数据

这个同样可以用Redis中的List去处理,比如微博某大V的评论数上百万,在页面上显示肯定只能显示最新的几十条评论,如果存在数据库中,用Mysql的SELECT limit 查询数据,会对所有数据进行排序,这样的代价机会非常大,但是如果使用Redis的List就可以使用lrange(“key”,0,100)方法,这样可以取出最近100条评论。

 

3. 计数器

因为微博有最大的Redis集群,我们还是拿微博举例,某明星发了一个主题“我们”的微博,点赞数量两天内几百万,对于这种情况,就可以使用Redis中的原子加减操作,在java中,我们知道i++或者i--并不是原子性的,也就意味着它并不是线程安全的,但是使用Redis就不会有这个问题,可以使用jedis.hincrBy("weiboid", "likes", 1);这样表示某微博点赞数量加1,在这里是线程安全的。

 

4. 排行榜,取TOP N数据

结合本文第二部分介绍的Sorted Set,我们可以取出TOP N的数据,比如有100W用户参与比赛,或者100W用户微博,我们想取出比赛成绩最高的100个,或者最热的100条微博,在这里的比赛成绩或者微博热度都可以是权值(score),在缓存中操作,不需要进行排序,就能快速取出。

 

5. 排重与求并、差、交集

Redis使用Set,在第二部分Java程序中已经介绍,需要排重时,只需要往set集合中插入数据,Redis会自动做好去重操作,并且可以求任意两个缓存中的set集合的并、交、差集合。

 

6. Pub/Sub

Redis支持消息发布-订阅模式,非常适合聊天消息推送。

 

学习资料与参考文献:

http://try.redis.io/  有Redis初学者需要学习的基本命令,提供命令行界面。

http://redis.io/topics/introduction Redis基本介绍

http://www.csdn.net/article/2013-10-07/2817107-three-giant-share-redis-experience/1  Redis在国内外应用

http://www.cnblogs.com/whoamme/p/3532129.html Redis基本操作

http://www.360doc.com/content/15/0510/20/23016082_469494498.shtml Redis应用

posted @ 2016-04-17 02:23 般若一号 阅读(1002) 评论(0) 推荐(0) 编辑
摘要: Java研发工程师方向 实习面试, 面试官很和善,抱着和你聊一聊的心态和你聊天,总体感觉阿里面试特别偏向Java,我简略回忆一下。1. 介绍以前实习经历,以及设计的项目,我说了以前做过的公司内部使用的系统,面试官提出如果对于访问量特别大的情况下,你有哪些优化方案?设置缓存;数据库读写分离;2. 说一... 阅读全文
posted @ 2015-04-28 09:20 般若一号 阅读(644) 评论(0) 推荐(0) 编辑
摘要: Implement pow(x, n). 阅读全文
posted @ 2014-06-22 13:27 般若一号 阅读(398) 评论(0) 推荐(0) 编辑
摘要: Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string. If the last word does not exist, return 0. Note: A word is defined as a character sequence consists of non-space characters only. 阅读全文
posted @ 2014-06-21 17:49 般若一号 阅读(498) 评论(0) 推荐(0) 编辑
摘要: Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. 阅读全文
posted @ 2014-06-21 11:00 般若一号 阅读(347) 评论(0) 推荐(0) 编辑
摘要: Given two sorted integer arrays A and B, merge B into A as one sorted array. You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B are m and n respectively. 阅读全文
posted @ 2014-06-12 23:52 般若一号 阅读(391) 评论(0) 推荐(0) 编辑
摘要: 实现windows phone控制PC端PPT的播放 阅读全文
posted @ 2014-05-29 21:44 般若一号 阅读(1779) 评论(3) 推荐(4) 编辑
摘要: 二叉树递归遍历飞递归遍历、层序遍历、二叉树建立销毁、二叉树树高树深、二叉树的按顺序建立搜索树。 阅读全文
posted @ 2014-04-27 01:27 般若一号 阅读(508) 评论(0) 推荐(0) 编辑
摘要: 数据结构中的七种排序算法实现,没有写基数排序。 阅读全文
posted @ 2014-04-27 00:22 般若一号 阅读(416) 评论(0) 推荐(0) 编辑
摘要: Sudoku 阅读全文
posted @ 2013-12-22 16:04 般若一号 阅读(6265) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示