(Redis部分)

简答题

1、什么是redis?Redis是一个基于内存的使用c语言编写的key-value开源的nosql数据库
2、Redis持久化数据的方式有哪些?
1》PDB触发式持久化++
每秒钟触发一次
2》AOF
3、解决IT行业数据读取瓶颈的终极方案?读写分离
4、Redis如何实现读写分离?Redis本身支持读写分离,主节点可以读写数据、从节点只能读数据。配置redis的主从复制结构可实现读写分离
5、介绍哨兵机制?哨兵机制解决的问题:主节点宕机导致数据无法写入redis
在Redis的主从复制结构中,若没有哨兵机制的话,主节点宕机,数据将无法写入到redis集群。配置了哨兵机制的话,当主节点宕机的时候,哨兵会从原来的从节点服务器中选取一个当做主节点,接收外部数据的写入。一次实现主节点宕机之后redis仍然可以写入数据
6、NoSQL适用场景
•对数据高并发的读写
•对数据高可扩展性的
•速度够快,能够快速的存取数据
7、NoSQL不适用场景
•需要事务支持
•基于sql的结构化查询存储,处理复杂的关系,需要即席查询(用户自定义查询条件的查询)。
8、redis的特点
高效性:Redis读取的速度是110000次/s,写的速度是81000次/s
原子性:Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
支持多种数据结构:string(字符串);list(列表);hash(哈希),set(集合);zset(有序集合)
稳定性:持久化,主从复制(集群)
其他特性:支持过期时间,支持事务,消息订阅。
8、Redis持久化数据的方式的优缺点有哪些?
RDB方案优点
1、对性能影响最小。如前文所述,Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客户端请求的效率。

2、每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照(例如把每天0点的快照备份至其他存储媒介中),作为非常可靠的灾难恢复手段。

3、使用RDB文件进行数据恢复比使用AOF要快很多
RDB方案缺点
1、快照是定期生成的,所以在Redis crash(崩溃)时或多或少会丢失一部分数据。

2、如果数据集非常大且CPU不够强(比如单核CPU),Redis在fork子进程时可能会消耗相对较长的时间,影响Redis对外提供服务的能力。
AOF优点:
1、最安全,在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据

2、AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。

3、AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。
AOF的缺点:
1、AOF文件通常比RDB文件更大

2、性能消耗比RDB高

3、数据恢复速度比RDB慢

1、redis当中对字符串string的操作

下表列出了常用的 redis 字符串命令
CRUD 功能 示例
增 添加字符串 set hello world
设置多个KV mset AA AAA BB BBB CC CCC
设置过期时间 setex hello1 5 word1
key不存在时设置 setnx hello2 word22
查 查询字符串 get hello
查询部分 getrange hello 0 2
查询多key mget hello hello2 hello3
查询长度 strlen hello
改 修改字符串 set hello world2
追加 append hello 333
删 删除字符串 del hello
其他 现获取后设置 getset hello word222
替换 setrange hello22 2 AA
累加1 incr number
累加N incrby number 10
累加小数 incrbyfloat number 0.5
减一(只对integer有效) decr number
减N decrby number 3

2、redis当中对hash列表的操作

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)

下表列出了 redis hash 基本的相关命令:

CRUD 功能 示例
增 添加一个hash列表 hset hkey1 name zhangsan
不存在时添加 hsetnx hkey2 name lisi
一次设置多个值 hmset hkey3 name wangwu age 20 sex 1
查 查看数据 hget hkey1 name
查看是否存在 hexists hkey3 name
查询key下所有值 hgetall hkey3
查询key内所有的字段 hkeys hkey3
查询key的数据量 hlen hkey3
查询某一key内多字段的值 hmget hkey3 name age
改 修改数据 hset hkey1 name zhangsan2
删 删除key中的数据 hdel hkey3 sex
其他 数据累加(1-N) hincrby hkey number1 10
累加小数 hincrbyfloat hkey number1 0.5

3、redis当中对list列表的操作

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。

下表列出了列表相关的基本命令

增	添加一个或多个值到列表	lpush lkey1 zhangsan lisi
	将一个值插入到已存在的列表头部	lpushx lkey1 wangwuxxx
	向已经存在的列表中插入数据(右边插入)	rpush lkey1 AA  BB
	将一个值插入到已存在的列表尾部	rpushx  lkey1 ccc
	在某一数据之前插入	linsert lkey1 before lisi lisibefore
	在某一数据之后插入	linsert lkey1 after lisi lisiafter
查	查询list中所有数据 (-1表示所有)	lrange lkey1 0 -1
	通过索引查询数据	lindex lkey1 0
	查询列表长度	llen lkey1
改	通过索引修改数据	lset lkey1 5 eee
删	数据修剪(保留)	ltrim lkey1 4 6
	删除指定key数据	del lkey1
其他	移出并获取列表的第一个元素	lpop lkey1
	移出并获取列表的最后一个元素	rpop lkey1
	移除列表的最后一个元素,并将该元素添加到另一个列表并返回	rpoplpush lkey1 lkey2

4、redis操作set集合

redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

下表列出了 Redis 集合基本命令:

增	向集合添加一个或多个数据	sadd skey1  zhangsan  lisi
sadd skey2  wangwu  lisi
查	查询集合所有数据	smembers skey1
	查询集合内数据总量	scard skey1
	查询两个集合的差值	sdiff skey1 skey2
	查询差值并将结果写入新集合	sdiffstore  skey3  skey1 skey2
	查询两个集合交集	sinter skey1 skey2
	查询两个集合交集结果写入新集合	sinterstore skey4 skey1 skey2
	查询某一数据是否包含在集合中	sismember skey1 zhangsan
	返回集合内随机的N个数据	srandmember skey2 2
	查询并集	sunion skey1  skey2
	查询并集结果写入新集合	sunionstore skeyn  skey1  skey2
改	将数据在一个集合移动到另一个集合	smove skey1 skey2 zhangsan
删	移除结果中的某个数据	srem skey2 zhangsan

5、redis中对key的操作

下表给出了与 Redis 键相关的基本命令:

查	查询所有符合模式的key	Keys *
	查询剩余过期时间(毫秒)	pttl  hkey1
	查询剩余过期时间(秒)	ttl  hkey1
	在数据库中随机回返一个key	randomkey
	查询key对应数据的类型	Type hkey1  
改	对key进行重命名	Rename  hkey1  hkey10
删	删除存在的key	del BB
其他	判断key是否存在	exists AA
	为key 设置超时时间	expire AA 10
	为key 设置超时时间(毫秒)	pexpire CC  10000
	移除key的过期时间	persist hkey1

练习题一:

1、创建两个list  名字分别为ltest1    ltest2.
	2、Ltest1 从左到右为1 2 3 4 5 6 7 8 9,ltest2 从左到右为 f e d c b a 
	lpush ltest1 9 8 7 6 5 4 3 2 1
	lpush ltest2  a b c d e f
	3、在Ltest1的3 左边插入3333
	linsert ltest1 before 3 333 
	4、在6右边插入6666
	linsert ltest2 after 6 6666
	5、通过索引查询Ltest2 索引为3的数据
	lindex ltest2 3
	6、将ltest2的e 修改为EEE
	lset ltest2 e EEE 
	7、只保留ltest2的EEE d c b
	ltrim ltest2 1 4
	8、移除ltest1右边一个数据并插入ltest2的左边
	rpoplpush ltest1 ltest2

练习题二:

练习:添加set 集合 setdemo1(aa,bb,cc,dd,ee,ff)    setdemo2(11,22,33,dd,ee,ff)
	sadd setdemo1 aa bb cc dd ee ff
	sadd setdemo2 11 22 33 dd ee ff
	将两个集合的交集写入setdemo3
	sinterstore setdemo3 setdemo1 setdemo2
	将两个集合的并集写入setdemo4
	sunion setdemo4 setdemo1 setdemo2
	将setdemo2集合与setdemo1集合的差集写入setdemo5
	sdiffstore setdemo5 setdemo2 setdemo1
	将setdemo2内的11 移动到setdemo1内
	smove setdemo2 setdemo1 11
 	删除setdemo1内的bb
	srem setdemo1 bb

Redis的JavaAPI

文档API

public class Redis01 {
    private JedisPool jedisPool;
    private JedisPoolConfig config;

    @BeforeTest
    public void redisConnectionPool(){
        config = new JedisPoolConfig();
        config.setMaxIdle(10);
        config.setMaxWaitMillis(3000);
        config.setMaxTotal(50);
        config.setMinIdle(5);
        jedisPool = new JedisPool(config, "node01", 6379);
    }
    @AfterTest
    public void closePool(){
        jedisPool.close();
    }

    /**
     * Redis操作Set
     */
    public void RedisSet(){
        Jedis resource = jedisPool.getResource();
        //添加数据
        resource.sadd("setkey", "setvalue1", "setvalue1", "setvalue2", "setvalue3");
        //查询数据
        Set<String> setkey = resource.smembers("setkey");
        for (String s : setkey) {
            System.out.println(s);
        }
        //移除掉一个数据
        resource.srem("setkey","setvalue3");
        resource.close();
    }
    /**
     * Redis对列表进行操作
     */
    public void RedisList(){
        Jedis resource = jedisPool.getResource();
        //从左边插入元素
        resource.lpush("listkey","listvalue1","listvalue1","listvalue2");

        //从右边移除元素
        resource.rpop("listkey");
        //获取所有值
        List<String> listkey = resource.lrange("listkey", 0, -1);
        for (String s : listkey) {
            System.out.println(s);
        }
        resource.close();
    }
    /**
     * Redis对字符串进行操作
     */
    @Test
    public void RedisString(){
        Jedis resource = jedisPool.getResource();
        //添加
//        resource.set("name","zhangsan");
        //获取
//        String name = resource.get("name");
//        System.out.println(name);
        //修改
//        resource.set("name","lisi");
        //删除
//        resource.del("name");
        //实现整形数据的增长操作
//        resource.incr("StingplayInt");
        resource.incrBy("StingplayInt",3);
        resource.close();
    }
}

习题API

public class Redis02 {
    private JedisPool jedisPool;
    private JedisPoolConfig config;

    @BeforeTest
    public void redisConnectionPool(){
        config = new JedisPoolConfig();
        config.setMaxIdle(10);
        config.setMaxWaitMillis(3000);
        config.setMaxTotal(50);
        config.setMinIdle(5);
        jedisPool = new JedisPool(config, "node01", 6379);
    }
    @AfterTest
    public void closePool(){
        jedisPool.close();
    }
    @Test
    public void set(){
        Jedis resource = jedisPool.getResource();
        //添加set 集合 setdemo1(aa,bb,cc,dd,ee,ff)    setdemo2(11,22,33,dd,ee,ff)
        resource.sadd("setdemo1", "aa", "bb", "cc", "dd","ee","ff");
        resource.sadd("setdemo2", "11", "22", "33", "dd","ee","ff");
//        将两个集合的交集写入setdemo3
        resource.sinterstore("setdemo3","setdemo1","setdemo2");
//        将两个集合的并集写入setdemo4
        resource.sunionstore("setdemo4","setdemo1","setdemo2");
//        将setdemo2集合与setdemo1集合的差集写入setdemo5
        resource.sdiffstore("serdemo5","setdemo2","setdemo1");
//        将setdemo2内的11 移动到setdemo1内
        resource.smove("setdemo2","setdemo1","11");
//        删除setdemo1内的bb
        resource.srem("serdemo1","bb");
        //查询数据
        Set<String> setkey = resource.smembers("setdemo1");
        for (String s : setkey) {
            System.out.println(s);
        }

        resource.close();
    }
    @Test
    public void RedisList(){
        Jedis resource = jedisPool.getResource();
        //1、创建两个list  名字分别为ltest1    ltest2.
        //	2、Ltest1 从左到右为1 2 3 4 5 6 7 8 9,ltest2 从左到右为 f e d c b a
        resource.lpush("ltest1","9","8","7","6","5","4","3","2","1");
        resource.lpush("ltest2","a","b","c","d","e","f");
        //3、在Ltest1的3 左边插入3333
        resource.linsert("ltest1",BinaryClient.LIST_POSITION.BEFORE,"3", "3333");
        //4、在6右边插入6666
        resource.linsert("ltest1",BinaryClient.LIST_POSITION.BEFORE,"6", "6666");
        //5、通过索引查询Ltest2 索引为3的数据
        resource.lindex("ltest2",3);
        //6、将ltest2的e 修改为EEE
        resource.lset("ltest2",1,"EEE");
       // 7、只保留ltest2的EEE d c b
        resource.ltrim("ltest2",1,4);
//        8、移除ltest1右边一个数据并插入ltest2的左边
        resource.rpoplpush("ltest2","ltest1");
        //获取所有值
        List<String> listkey = resource.lrange("ltest1", 0, -1);
        for (String s : listkey) {
            System.out.println(s);
        }
        List<String> listkey2 = resource.lrange("ltest2", 0, -1);
        for (String s : listkey2) {
            System.out.println(s);
        }
        resource.close();
    }
}