• 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
    
  • 相关阅读:
    tar解压出错
    HUNNU11352:Digit Solitaire
    cocos2d-x 二进制文件的读写
    电子支付概述(1)
    新一批思科电子书下载
    HUNNU11354:Is the Name of This Problem
    POJ 3181 Dollar Dayz 简单DP
    Spring中IOC和AOP的详细解释
    atheros wifi 动因分析
    Android ActionBar相关
  • 原文地址:https://www.cnblogs.com/JoshuaYu/p/15042036.html
Copyright © 2020-2023  润新知