zoukankan      html  css  js  c++  java
  • Redis入门和Java利用jedis操作redis

    Redis入门和Java利用jedis操作redis

    Redis介绍

    Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。

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

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

    优势:

    • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
    • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
    • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
    • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

    本文旨在介绍Redis数据库的使用,具体底层的实现逻辑还需要漫长的学习,推荐《Redis设计与实现》这本书,继续学习Redis的具体实现。

    Redis的常用命令

    首先搭建好Redis的环境后,在控制台输入redis-cli,便进入redis的操作会话中

    PS C:Users12392> redis-cli
    127.0.0.1:6379>
    

    通过select关键字选择数据库

    127.0.0.1:6379> select 1
    OK
    127.0.0.1:6379[1]>
    

    这里选择到第一个数据库

    redis常用键的命令

    127.0.0.1:6379[1]> flushdb
    OK
    127.0.0.1:6379[1]> set "user" "hello"
    OK
    127.0.0.1:6379[1]> keys *
    1) "user"
    127.0.0.1:6379[1]> type "user"
    string
    127.0.0.1:6379[1]> set "user" "hello1" # 更改user的值为hello1
    OK
    127.0.0.1:6379[1]> get "user" # 获取user的值
    "hello1"
    127.0.0.1:6379[1]> del "user" #删除user
    (integer) 1
    127.0.0.1:6379[1]> keys * 
    (empty list or set)
    127.0.0.1:6379[1]> mset "user1" "hello1" "user2" "hello2" # 批量设置键值对
    OK
    127.0.0.1:6379[1]> keys * 
    1) "user2"
    2) "user1"
    127.0.0.1:6379[1]> mget "user1" "user2" # 批量获取键值对
    1) "hello1"
    2) "hello2"
    127.0.0.1:6379[1]> exists "user1" # 查看是否存在键
    (integer) 1
    127.0.0.1:6379[1]> expire "user1" 10 # 设置user1的过期时间为10秒
    (integer) 1
    127.0.0.1:6379[1]> keys *
    1) "user2"
    127.0.0.1:6379[1]> pexpire "user2" 1000 # 设置user2的过期时间为1000毫秒
    (integer) 1
    127.0.0.1:6379[1]> keys *
    (empty list or set)
    127.0.0.1:6379[1]> set "user" "hello"
    OK
    127.0.0.1:6379[1]> expire "user" 20
    (integer) 1
    127.0.0.1:6379[1]> persist "user" # 取消user的过期时间
    (integer) 1
    127.0.0.1:6379[1]> keys *
    1) "user"
    

    string类型

    127.0.0.1:6379[1]> flushdb
    OK
    127.0.0.1:6379[1]> set "string" "0123456789"
    OK
    127.0.0.1:6379[1]> get "string"
    "0123456789"
    127.0.0.1:6379[1]> getrange "string" 0 5 # 取字符串从0开始到5的位置
    "012345"
    127.0.0.1:6379[1]> getrange "string" 0 -1 # 取整个字符串
    "0123456789"
    127.0.0.1:6379[1]> getset "string" "hello" # 获取键并设置值
    "0123456789"
    127.0.0.1:6379[1]> get "string"
    "hello"
    127.0.0.1:6379[1]> setnx "testkey" "testvalue" # 如果不存在当前的键,那么就插入,返回1成果,0失败
    (integer) 1
    127.0.0.1:6379[1]> setnx "string" "123" 
    (integer) 0
    127.0.0.1:6379[1]> setex "user" 100 "123" # 设置user的过期时间为100秒
    OK
    127.0.0.1:6379[1]> incr "user" # user增加1
    (integer) 124
    127.0.0.1:6379[1]> decr "user" #user减少1
    (integer) 123
    127.0.0.1:6379[1]> incrby "user" 20 # user增加20 
    (integer) 143
    127.0.0.1:6379[1]> decrby "user" 20 # user减少20
    (integer) 123
    127.0.0.1:6379[1]> append "string" "world" # 字符串尾部加上值
    (integer) 10
    127.0.0.1:6379[1]> get "string" 
    "helloworld"
    127.0.0.1:6379[1]> strlen "string" # 获取字符串长度
    (integer) 10
    

    hash类型

    127.0.0.1:6379[1]> flushdb
    OK
    127.0.0.1:6379[1]> hset "hash" 1 1 # 设置hash键,对应的map中存入键值对1 1
    (integer) 1
    127.0.0.1:6379[1]> hget "hash" 1 # 获取hash中键1的值
    "1"
    127.0.0.1:6379[1]> hmset "hash" 2 2 3 3 # 批量设置hash中的键值对
    OK
    127.0.0.1:6379[1]> hmget "hash" 2 3 # 批量获取hash中的键值对
    1) "2"
    2) "3"
    127.0.0.1:6379[1]> hgetall "hash" # 获取hash中全部的键值对
    1) "1"
    2) "1"
    3) "2"
    4) "2"
    5) "3"
    6) "3"
    127.0.0.1:6379[1]> hexists "hash" 1 # hash中是否存在键1
    (integer) 1
    127.0.0.1:6379[1]> hexists "hash" 4
    (integer) 0
    127.0.0.1:6379[1]> hsetnx "hash" 1 1 # 如果hash中没有键1,就设置键值对1 1,返回1,否则返回0
    (integer) 0
    127.0.0.1:6379[1]> hsetnx "hash" 4 4
    (integer) 1
    127.0.0.1:6379[1]> hincrby "hash" 1 20 # 设置hash中键1的值增加20
    (integer) 21
    127.0.0.1:6379[1]> hdel "hash" 1
    (integer) 1
    127.0.0.1:6379[1]> hkeys "hash" # 仅获取全部的键
    1) "2"
    2) "3"
    3) "4"
    127.0.0.1:6379[1]> hvals "hash" #仅获取全部的值
    1) "2"
    2) "3"
    3) "4"
    127.0.0.1:6379[1]> hlen "hash" #获取hash的大小
    (integer) 3
    

    list类型

    127.0.0.1:6379[1]> lpush "list" a b c # 左插入a b c
    (integer) 3
    127.0.0.1:6379[1]> rpush "list" x y z # 右插入x y z
    (integer) 6
    127.0.0.1:6379[1]> lrange "list" 0 -1 # 遍历列表
    1) "c"
    2) "b"
    3) "a"
    4) "x"
    5) "y"
    6) "z"
    127.0.0.1:6379[1]> lpop "list" # 左弹出一个元素,并返回该元素
    "c"
    127.0.0.1:6379[1]> rpop "list" # 右弹出一个元素,并返回该元素
    "z"
    127.0.0.1:6379[1]> lrange "list" 0 -1
    1) "b"
    2) "a"
    3) "x"
    4) "y"
    127.0.0.1:6379[1]> llen "list" # 列表长度
    (integer) 4
    127.0.0.1:6379[1]> lpush "list" b b b
    (integer) 7
    127.0.0.1:6379[1]> lrem "list" 2 b # 从左开始删除两个值为b的元素
    (integer) 0
    # Redis Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。
    # lrem key count value
    # count 的值可以是以下几种:
    # count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
    # count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
    # count = 0 : 移除表中所有与 VALUE 相等的值。
    127.0.0.1:6379[1]> lrange "list" 0 -1
    1) "b"
    2) "b"
    3) "a"
    4) "x"
    5) "y"
    127.0.0.1:6379[1]> lindex "list" 2 # 获取list中下标为2的值
    "a"
    127.0.0.1:6379[1]> lset "list" 2 n # 设置list中下标为2的元素值为n
    OK
    127.0.0.1:6379[1]> lrange "list" 0 -1
    1) "b"
    2) "b"
    3) "n"
    4) "x"
    5) "y"
    127.0.0.1:6379[1]> ltrim "list" 1 3 # 保留list中下标1到3的元素,其余删除
    OK
    127.0.0.1:6379[1]> lrange "list" 0 -1
    1) "b"
    2) "n"
    3) "x"
    127.0.0.1:6379[1]> linsert "list" before b n # 在list中的n前面加上b
    (integer) 4
    127.0.0.1:6379[1]> linsert "list" after x n # 在list中的n后面加上x
    (integer) 5
    127.0.0.1:6379[1]> lrange "list" 0 -1
    1) "n"
    2) "b"
    3) "n"
    4) "x"
    5) "n"
    127.0.0.1:6379[1]> rpoplpush "list" "newlist" # 源list右端弹出一个元素并插入newlist左端,并返回该元素
    "n"
    127.0.0.1:6379[1]> lrange "newlist" 0 -1
    1) "n"
    
    # 利用好list数据结构,可以构造出栈和队列等数据结构
    

    set类型

    127.0.0.1:6379[1]> sadd "set" 1 # 在set中添加一个元素1
    (integer) 1
    127.0.0.1:6379[1]> sadd "set" 2 3 4 5 #在set中批量添加元素
    (integer) 4
    127.0.0.1:6379[1]> smembers "set" # 获取set中所有元素
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    127.0.0.1:6379[1]> srem "set" 5 # 删除set中值为5的元素
    (integer) 1
    127.0.0.1:6379[1]> smembers "set" 
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    127.0.0.1:6379[1]> scard "set" # 获取set中元素个数
    (integer) 4
    127.0.0.1:6379[1]> sadd "set2" 3 4 5 6
    (integer) 4
    127.0.0.1:6379[1]> sdiff "set" "set2" # set和set2的差集
    1) "1"
    2) "2"
    127.0.0.1:6379[1]> sinter "set" "set2" # set和set2的交集
    1) "3"
    2) "4"
    127.0.0.1:6379[1]> sunion "set" "set2" # set和set2的并集
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    6) "6"
    127.0.0.1:6379[1]> srandmember "set" # 随机获取一个set中的元素
    "3"
    127.0.0.1:6379[1]> srandmember "set" 2 # 随机获取多个set中的元素
    1) "3"
    2) "1"
    127.0.0.1:6379[1]> spop "set" # 随机删除一个set中元素
    "2"
    127.0.0.1:6379[1]> spop "set" 2 # 随机删除两个set中元素
    1) "3"
    2) "4"
    127.0.0.1:6379[1]> smembers "set"
    1) "1"
    

    zset(有序集合)

    127.0.0.1:6379[1]> zadd "zset" 1 one # 添加一个权值为1的元素one
    (integer) 1
    127.0.0.1:6379[1]> zadd "zset" 2 two 3 three # 批量添加
    (integer) 2
    127.0.0.1:6379[1]> zrange "zset" 0 -1 withscores # 返回集合元素按照分数排序
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    127.0.0.1:6379[1]> zcard "zset" # 获取集合元素
    (integer) 3
    127.0.0.1:6379[1]> zrangebyscore "zset" 2 3 withscores # 按分数获取集合中元素
    1) "two"
    2) "2"
    3) "three"
    4) "3"
    127.0.0.1:6379[1]> zrangebyscore "zset" 1 3 withscores limit 1 2 # 获取元素后分页返回
    1) "two"
    2) "2"
    3) "three"
    4) "3"
    127.0.0.1:6379[1]>  zrevrangebyscore "zset" 3 1 withscores # 按分数获取元素从大到小输出
    1) "three"
    2) "3"
    3) "two"
    4) "2"
    5) "one"
    6) "1"
    127.0.0.1:6379[1]> zcount "zset" 2 3 # 权值范围在2~3之间的元素个数
    (integer) 2
    127.0.0.1:6379[1]> zadd "zset" 4 four
    (integer) 1
    127.0.0.1:6379[1]> zrem "zset" one four # 删除元素one和four
    (integer) 2
    127.0.0.1:6379[1]> zadd "zset" 1 one 4 four
    (integer) 1
    127.0.0.1:6379[1]> zremrangebyrank "zset" 2 3 # 删除排名2~3的元素
    (integer) 1
    127.0.0.1:6379[1]> zadd "zset" 2 two 3 three
    (integer) 1
    127.0.0.1:6379[1]> zremrangebyscore "zset" 2 3 # 删除分数在2~3之间的元素
    (integer) 2
    

    Redis 事务

    Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

    • 批量操作在发送 EXEC 命令前被放入队列缓存。
    • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
    • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
    127.0.0.1:6379[1]> multi # 开启事务OK127.0.0.1:6379[1]> set a aQUEUED127.0.0.1:6379[1]> set b bQUEUED127.0.0.1:6379[1]> exec # 执行1) OK2) OK
    

    Jedis连接Redis

    准备

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

    Jedis对象不是线程安全的,在多线程下使用同一个Jedis对象会出现并发问题,为了避免每次使用Jedis对象时都需要重新创建,Jedis提供了JedisPool。Jedis是线程安全的连接池。下面是jedispool类的代码

    import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;public class jedisPool {    private jedisPool() {}    private static JedisPool jedisPool;    private static int maxtotal = 100; // 最大连接数    private static int maxwaitmillis = 3000; // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1    private static String host = "127.0.0.1";    private static int port = 6379;    /*创建连接池*/    static{        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();        jedisPoolConfig.setMaxTotal(maxtotal);        jedisPoolConfig.setMaxWaitMillis(maxwaitmillis);        jedisPool = new JedisPool(jedisPoolConfig, host, port);    }    /*获取jedis*/    public static Jedis getJedis(){        return jedisPool.getResource();    }    /*关闭Jedis*/    public static void close(Jedis jedis){        if(jedis!=null){            jedis.close();        }    }}
    

    使用

    在需要使用redis时,从连接池中获取jedis实例,通过idea的智能提示可以获取到jedis的全部方法,由于过多所以这里不做介绍,其中的用发和上文命令行才做jedis几乎一样。下面仅仅是一个小demo

    @Testpublic void Test() {    Jedis jedis = jedisPool.getJedis();    jedis.set("1", "1");    jedis.mset("2", "2", "3", "3");    System.out.println(jedis.get("1"));}
    

    下面是一些特殊用法:

    jedis的事务执行:

    @Testpublic void Test() {    Jedis jedis = jedisPool.getJedis();    Transaction t = jedis.multi();    t.set("fool", "bar");    Response<String> result1 = t.get("fool");    t.zadd("foo", 1, "barowitch");    t.zadd("foo", 0, "barinsky");    t.zadd("foo", 0, "barikoviev");    Response<Set<String>> sose = t.zrange("foo", 0, -1);    t.exec();    System.out.println(result1.get());    System.out.println(sose.get());    // 另一种方式    // List<Object> allResults = t.exec();    // System.out.println(allResults);}
    

    管道操作:

    如果遇到一次性存储大量数据,又不需要返回结果的时,可以采用管道操作来节约时间,下面时测试代码来测试管道插入和查询的性能:

    public class test1 {    static Long start = 0L;    static Long time = 0L;    @Test    public void Test() {        Jedis jedis = jedisPool.getJedis();        jedis.flushAll();        start();        for(int i = 0; i<10000; i++){            String content = i + "";            jedis.set(content, content);        }        end();        System.out.println("未使用管道插入数据,耗时:" + time + "ms");        jedis.flushAll();        Pipeline p = jedis.pipelined();        start();        for(int i = 0; i<10000; i++){            String content = i + "";            p.set(content, content);        }        p.sync();        end();        System.out.println("已使用管道插入数据,耗时:" + time + "ms");        Map result = new HashMap<String,String>(10000);        start();        for(int i = 0; i<10000; i++){            String content = i + "";            String value = jedis.get(content);            result.put(content,value);        }        end();        System.out.println("未使用管道查询数据,耗时:" + time + "ms");        result.clear();        start();        Map<String,Response> responses = new HashMap<String, Response>(10000);        for(int i = 0;i<10000;i++){            String content = i + "";            Response<String> response = p.get(content);            responses.put(content, response);        }        for(String key:responses.keySet()){            result.put(key,responses.get(key));        }        end();        System.out.println("已使用管道查询数据,耗时:" + time + "ms");        p.close();    }    public static void start(){        start = System.currentTimeMillis();    }    public static void end(){        time = System.currentTimeMillis() - start;    }}
    

    输出:

    未使用管道插入数据,耗时:550ms已使用管道插入数据,耗时:22ms未使用管道查询数据,耗时:409ms已使用管道查询数据,耗时:5ms
    
  • 相关阅读:
    word设置的密码忘了怎么办?
    Navicat Report Viewer 设置 HTTP 的方法
    如何处理Navicat Report Viewer 报表
    excel密码忘记了怎么办
    Beyond Compare文本比较搜索功能详解
    Popular Cows POJ
    Problem B. Harvest of Apples HDU
    网络流模型整理
    The Shortest Statement CodeForces
    Vasya and Multisets CodeForces
  • 原文地址:https://www.cnblogs.com/JoshuaYu/p/15042036.html
Copyright © 2011-2022 走看看