zoukankan      html  css  js  c++  java
  • Redis介绍及Jedis基础操作

    1.Redis简介

        Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

        Redis 与其他 key - value 缓存产品有以下三个特点:

    1. Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
    2. Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
    3. Redis支持数据的备份,即master-slave模式的数据备份。

    2.Redis优势

    1. 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
    2. 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
    3. 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
    4. 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
    5. Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

    3.linux环境下安装Redis

        1.下载地址:http://redis.io/download,下载最新版本的linux版本Redis。

        2.本教程使用的最新文档版本为 4.0.6,下载文件后,上传到linux服务器上面,并解压安装。

         操作指令为:$ tar xzf redis-4.0.6.tar.gz     $ cd redis-4.0.6    $ make 

        3.make成功执行完后 redis- 4.0.6目录会生成src 目录,在一次执行命令:$ make install

             

        4.启动redis服务,使用默认配置方式启动:进入到redis-4.0.6/src目录,执行启动命令:redis-server 

        

        注意:这里直接执行Redis-server 启动的Redis服务,是在前台直接运行的(效果如上图),也就是说,执行完该命令后,如果Linux关闭当前会话,则Redis服务也随即关闭。正常情况下,启动Redis服务需要从后台启动,并且指定启动配置文件。 

    后台启动redis服务

    1. 首先编辑conf文件,将daemonize属性改为yes(表明需要在后台运行),并指定ip地址,开放redis端口号:6379。操作指令为:cd redis-4.0.6/ vi redis.conf
    2. 再次启动redis服务,并指定启动服务配置文件:  redis-server /usr/local/redis/etc/redis.conf    
    3. 在防火墙中开放端口:6379

         

        在本地电脑上,安装一个redis客户端连接工具,如:redisclient-win32.x86.1.5。利用连接工具可方便查看redis中设置的缓存数据,连接如图所示:   

    4.jedis操作Redis介绍

        jedis 是 Redis 官方首选的 Java 客户端开发包,上手比较容易。jedis提供了以下三种操作方式:

    1. 单机单连接方式:此方式仅建议用于开发环境做调试用。
    2. 单机连接池方式:此方式适用于仅使用单个Redis实例的场景
    3. 多机分布式+连接池方式:此方式适用规模较大的系统,往往会有多个Redis实例做负载均衡。并且还实现主从备份,当主实例发生故障时,切换至从实例提供服务。
    4. redis3.0推出JedisCluster。使用JedisCluster连接使用这种方式时,默认Redis已经进行了集群处理,JedisCluster即针对整个集群的连接.

     

     jedis操作redis模式

    (1)事务方式(Transactions)

        所谓事务,即一个连续操作,是否执行是一个事务,要么完成,要么失败,没有中间状态。而redis的事务很简单,他主要目的是保障,一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令,也就是事务的连贯性。

       测试截图

     

    (2)管道(Pipelining)

       管道是一种两个进程之间单向通信的机制。那再redis中,为何要使用管道呢?有时候,需要采用异步的方式,一次发送多个指令,并且,不同步等待其返回结果。这样可以取得非常好的执行效率。管道模式测试代码:

      @Test
        public void jedisPipelined() {
            Jedis jedis = new Jedis("192.168.210.128", 6379);
            Pipeline pipeline = jedis.pipelined();
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                pipeline.set("p" + i, "p" + i);
            }
            List<Object> results = pipeline.syncAndReturnAll();
            long end = System.currentTimeMillis();
            System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
            jedis.disconnect();
        }

       注意:事务和管道都是异步模式。在事务和管道中不能同步查询结果。如下代码操作为非法操作:

    Transaction tx = jedis.multi();  
     for (int i = 0; i < 100000; i++) {  
         tx.set("t" + i, "t" + i);  
     }  
       System.out.println(tx.get("t1000").get());  //不允许  
       List<Object> results = tx.exec();  

    (3)管道中调用事务

        在某种需求下,需要异步执行命令,但是,又希望多个命令是有连续的,所以可采用管道加事务的调用方式。jedis是支持在管道中调用事务的。

    (4)分布式直连同步调用与分布式连接池同步调用

        这个是分布式直接连接,并且是同步调用,每步执行都返回执行结果。如果,分布式调用代码是运行在线程中,那么分布式直连同步调用方式就不合适了,因为直连方式是非线程安全的,这个时候需使用选择连接池调用。案例代码:

    //分布式直接链接并同步调用
    public void jedisShardNormal() {  
        List<JedisShardInfo> shards = Arrays.asList(  
                new JedisShardInfo("localhost",6379),  
                new JedisShardInfo("localhost",6380));  
       
        ShardedJedis sharding = new ShardedJedis(shards);  
       
        long start = System.currentTimeMillis();  
        for (int i = 0; i < 100000; i++) {  
            String result = sharding.set("sn" + i, "n" + i);  
        }  
        long end = System.currentTimeMillis();  
        System.out.println("Simple@Sharing SET: " + ((end - start)/1000.0) + " seconds");  
       
        sharding.disconnect();  
    }  
    //分布式结合线程池使用
    public void jedisShardSimplePool() {  
        List<JedisShardInfo> shards = Arrays.asList(  
                new JedisShardInfo("localhost",6379),  
                new JedisShardInfo("localhost",6380));  
       
        ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);  
       
        ShardedJedis one = pool.getResource();  
       
        long start = System.currentTimeMillis();  
        for (int i = 0; i < 100000; i++) {  
            String result = one.set("spn" + i, "n" + i);  
        }  
        long end = System.currentTimeMillis();  
        pool.returnResource(one);  
        System.out.println("Simple@Pool SET: " + ((end - start)/1000.0) + " seconds");  
       
        pool.destroy();  
    }  

    (5)分布式直连异步调用与分布式连接池异步调用

        操作与同步相对,案例代码如下:

    //分布式连接池异步调用测试 线程池使用
    public void jedisShardPipelinedPool() {  
        List<JedisShardInfo> shards = Arrays.asList(  
                new JedisShardInfo("localhost",6379),  
                new JedisShardInfo("localhost",6380));  
       
        ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);  
       
        ShardedJedis one = pool.getResource();  
       
        ShardedJedisPipeline pipeline = one.pipelined();  
       
        long start = System.currentTimeMillis();  
        for (int i = 0; i < 100000; i++) {  
            pipeline.set("sppn" + i, "n" + i);  
        }  
        List<Object> results = pipeline.syncAndReturnAll();  
        long end = System.currentTimeMillis();  
        pool.returnResource(one);  
        System.out.println("Pipelined@Pool SET: " + ((end - start)/1000.0) + " seconds");  
        pool.destroy();  
    }  

    (6)安全线程连接池(JedisPool)   

       注意Jedis对象并不是线程安全的,在多线程下使用同一个Jedis对象会出现并发问题。为了避免每次使用Jedis对象时都需要重新构建,Jedis提供了JedisPoolJedisPool是基于Commons Pool 2实现的一个线程安全的连接池。

    //线程池模式使用测试:   
       JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(10);
        JedisPool pool = new JedisPool(jedisPoolConfig, "localhost", 6379);
    
        Jedis jedis = null;
        try{
            jedis = pool.getResource();
            jedis.set("pooledJedis", "hello jedis pool!");
            System.out.println(jedis.get("pooledJedis"));
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            //还回pool中
            if(jedis != null){
                jedis.close();
            }
        }
        pool.close();

    (7)多机分布式集合连接池使用

        此方式适用规模较大的系统,往往会有多个Redis实例做负载均衡。并且还实现主从备份,当主实例发生故障时,切换至从备用实例提供服务。如服务器1挂掉后,可用服务器2继续支撑redis缓存处理。测试代码:

    **
     * Description:  多机分布式+连接池方式:
     * Copyright:  2018 CSNT. All rights reserved.
     * Company:CSNT
     *
     * @author wangling
     * @version 1.0
     */
    public class MultipleJedisPoolTest {
    
        static JedisPoolConfig config;
        static ShardedJedisPool sharedJedisPool;
    
        static {
            // 生成多机连接List
            List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
            shards.add( new JedisShardInfo("127.0.0.1", 6379) );
            shards.add( new JedisShardInfo("192.168.210.128", 6379) );
    
            // 初始化连接池配置对象
            config = new JedisPoolConfig();
            config.setMaxIdle(10);
            config.setMaxTotal(30);
            config.setMaxWaitMillis(2*1000);
            // 实例化连接池
            sharedJedisPool = new ShardedJedisPool(config, shards);
    
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // 从连接池获取Jedis连接
            ShardedJedis shardedJedisConn = sharedJedisPool.getResource();
            shardedJedisConn.set("Lemon", "Hello,my name is Lemon");
            System.out.println(shardedJedisConn.get("Lemon"));
            // 释放连接
            close(shardedJedisConn, sharedJedisPool);
    
    }
        private static void close(ShardedJedis shardedJedis,ShardedJedisPool sharedJedisPool){
            if(shardedJedis!=null &&sharedJedisPool!=null){
                sharedJedisPool.returnResource(shardedJedis);
            }
            if(sharedJedisPool!=null){
                sharedJedisPool.destroy();
            }
        }
    }

    5.Redis常用命令

    1 连接操作命令

    • quit:关闭连接(connection)
    • auth:简单密码认证
    • help cmd: 查看cmd帮助,例如:help quit

    2 持久化

    • save:将数据同步保存到磁盘
    • bgsave:将数据异步保存到磁盘
    • lastsave:返回上次成功将数据保存到磁盘的Unix时戳
    • shutdown:将数据同步保存到磁盘,然后关闭服务

    3 远程服务控制

    • info:提供服务器的信息和统计
    • monitor:实时转储收到的请求
    • slaveof:改变复制策略设置
    • config:在运行时配置Redis服务器

    4 对key操作的命令

    • exists(key):确认一个key是否存在
    • del(key):删除一个key
    • type(key):返回值的类型
    • keys(pattern):返回满足给定pattern的所有key
    • randomkey:随机返回key空间的一个
    • keyrename(oldname, newname):重命名key
    • dbsize:返回当前数据库中key的数目
    • expire:设定一个key的活动时间(s)
    • ttl:获得一个key的活动时间
    • select(index):按索引查询
    • move(key, dbindex):移动当前数据库中的key到dbindex数据库
    • flushdb:删除当前选择数据库中的所有key
    • flushall:删除所有数据库中的所有key

    5 String

    • set(key, value):给数据库中名称为key的string赋予值value
    • get(key):返回数据库中名称为key的string的value
    • getset(key, value):给名称为key的string赋予上一次的value
    • mget(key1, key2,…, key N):返回库中多个string的value
    • setnx(key, value):添加string,名称为key,值为value
    • setex(key, time, value):向库中添加string,设定过期时间time
    • mset(key N, value N):批量设置多个string的值
    • msetnx(key N, value N):如果所有名称为key i的string都不存在
    • incr(key):名称为key的string增1操作
    • incrby(key, integer):名称为key的string增加integer
    • decr(key):名称为key的string减1操作
    • decrby(key, integer):名称为key的string减少integer
    • append(key, value):名称为key的string的值附加value
    • substr(key, start, end):返回名称为key的string的value的子串

    6 List

    • rpush(key, value):在名称为key的list尾添加一个值为value的元素
    • lpush(key, value):在名称为key的list头添加一个值为value的 元素
    • llen(key):返回名称为key的list的长度
    • lrange(key, start, end):返回名称为key的list中start至end之间的元素
    • ltrim(key, start, end):截取名称为key的list
    • lindex(key, index):返回名称为key的list中index位置的元素
    • lset(key, index, value):给名称为key的list中index位置的元素赋值
    • lrem(key, count, value):删除count个key的list中值为value的元素
    • lpop(key):返回并删除名称为key的list中的首元素
    • rpop(key):返回并删除名称为key的list中的尾元素
    • blpop(key1, key2,… key N, timeout):lpop命令的block版本。
    • brpop(key1, key2,… key N, timeout):rpop的block版本。
    • rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部

    7 Set

    • sadd(key, member):向名称为key的set中添加元素member
    • srem(key, member) :删除名称为key的set中的元素member
    • spop(key) :随机返回并删除名称为key的set中一个元素
    • smove(srckey, dstkey, member) :移到集合元素
    • scard(key) :返回名称为key的set的基数
    • sismember(key, member) :member是否是名称为key的set的元素
    • sinter(key1, key2,…key N) :求交集
    • sinterstore(dstkey, (keys)) :求交集并将交集保存到dstkey的集合
    • sunion(key1, (keys)) :求并集
    • sunionstore(dstkey, (keys)) :求并集并将并集保存到dstkey的集合
    • sdiff(key1, (keys)) :求差集
    • sdiffstore(dstkey, (keys)) :求差集并将差集保存到dstkey的集合
    • smembers(key) :返回名称为key的set的所有元素
    • srandmember(key) :随机返回名称为key的set的一个元素

    8 Hash

    • hset(key, field, value):向名称为key的hash中添加元素field
    • hget(key, field):返回名称为key的hash中field对应的value
    • hmget(key, (fields)):返回名称为key的hash中field i对应的value
    • hmset(key, (fields)):向名称为key的hash中添加元素field
    • hincrby(key, field, integer):将名称为key的hash中field的value增加integer
    • hexists(key, field):名称为key的hash中是否存在键为field的域
    • hdel(key, field):删除名称为key的hash中键为field的域
    • hlen(key):返回名称为key的hash中元素个数
    • hkeys(key):返回名称为key的hash中所有键
    • hvals(key):返回名称为key的hash中所有键对应的value
    • hgetall(key):返回名称为key的hash中所有的键(field)及其对应的value

    6.参考网址

    7.源码下载

    在Git上面下载:https://github.com/wuya11/jedisDemo

  • 相关阅读:
    解读tensorflow之rnn 的示例 ptb_word_lm.py
    tensorflow 的rnn的示例 ptb_word_lm.py 的完整代码
    python中decorator的用法及原理(一)
    android 6 (API 23) 及更高版本 面向 NDK 开发者的 Android 变更
    GCC选项_-Wl,-soname 及 DT_NEEDED 的解释
    一万小时天才理论
    好好说话!
    如何打造你的独立观点
    整理的艺术3
    读过的书记不住怎么办?
  • 原文地址:https://www.cnblogs.com/wlandwl/p/redis.html
Copyright © 2011-2022 走看看