Redis 学习笔记(1)

1 NoSQL 数据库

1.1 什么是NoSQL


NoSQL最常见的解释是“non-relational”, 很多人也说它是“Not Only SQL” 。NoSQL仅仅是一个概念,泛指非关系型的数据库。

区别于关系数据库,它们不保证关系数据的ACID特性。

1.2 NoSQL的特点


在讨论NoSQL的特点之前,我们先看看RDBMS的特点。

RDBMS:关系型数据库管理系统

  • 工具:MySQL、Oracle、SQL Server……
  • 应用:业务性数据存储系统:事务和稳定性
  • 特点:体现数据之间的关系,支持事务,保证业务完整性和稳定性,小数据量的性能也
    比较好
  • 开发:SQL

业务架构中的问题:以网站后台存储为例,当并发量很大,所有高并发全部直接请求MySQL,容易导致MySQL奔溃。

在这里插入图片描述

需求:能实现高并发的数据库,接受高并发请求。

NoSQL:Not Only SQL,非关系型数据库

  • 工具:Redis、HBASE、MongoDB……
  • 应用:一般用于高并发高性能场景下的数据缓存或者数据库存储
  • 特点:读写速度特别快,并发量非常高,相对而言不如RDBMS稳定,对事务性的支持不太友好
  • 开发:每种NoSQL都有自己的命令语法
  • 解决上面RDBMS的问题:使用高并发缓存实现读写分离
    • 读请求:读请求不读取MySQL,读取Redis
    • 写请求:写请求直接写入MySQL

在这里插入图片描述

  • RDBMS的特点
    • 场景:业务数据库
    • 特点:稳定性高、事务支持比较完善、小数据量性能好
  • NoSQL的特点
    • 应用场景
      • 高并发的读写
      • 海量数据读写
      • 高可扩展性
      • 速度快
    • 不适用场景
      • 需要事务支持
      • 基于sql的结构化查询存储,处理复杂的关系,需要即席查询(用户自定义查询条件的查询)
      • 稳定性和安全性要求高

1.3 NoSQL 数据库


  1. memcache
  • 很早出现的NoSql数据库
  • 数据都在内存中,一般不持久化
  • 支持简单的key-value模式
  • 一般是作为缓存数据库辅助持久化的数据库
  1. redis
  • 几乎覆盖了Memcache的绝大部分功能
  • 数据都在内存中,支持持久化,主要用作备份恢复
  • 除了支持简单的key-value模式,还支持多种数据结构的存储,比如 list、set、hash、zset等。
  • 一般是作为缓存数据库辅助持久化的数据库
  • 现在市面上用得非常多的一款内存数据库
  1. mongoDB
  • 高性能、开源、模式自由(schema free)的文档型数据库
  • 数据都在内存中, 如果内存不足,把不常用的数据保存到硬盘
  • 虽然是key-value模式,但是对value(尤其是json)提供了丰富的查询功能
  • 支持二进制数据及大型对象
  • 可以根据数据的特点替代RDBMS ,成为独立的数据库。或者配合RDBMS,存储特定的数据。
  1. HBase

HBase是Hadoop项目中的数据库。它用于需要对大量的数据进行随机、实时读写操作的场景中。HBase的目标就是处理数据量非常庞大的表,可以用普通的计算机处理超过10亿行数据,还可处理有数百万列元素的数据表。

2 Redis 介绍

2.1 Redis 基本介绍


Redis是当前比较热门的NoSQL系统之一。它是一个开源的、使用ANSI C语言编写的 key-value 存储系统(区别于MySQL的二维表格形式存储)。

和Memcache类似,但很大程度补偿了Memcache的不足,Redis数据都是缓存在计算机内存中,不同的是,Memcache只能将数据缓存到内存中,无法自动定期写入硬盘,这就表示,一断电或重启,内存清空,数据丢失。

2.2 Redis的应用场景


  1. 取最新N个数据的操作

比如典型获取网站最新文章,可以将最新的5000条评论ID放在Redis的List集合中,并将超出集合部分从数据库获取。

  1. 排行榜应用,取TOP N操作

这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,可以使用Redis的sorted set,将要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。

  1. 需要精准设定过期时间的应用

比如可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。

  1. 计数器应用

Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。

  1. Uniq操作,获取某段时间所有数据排重值

这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。

  1. 实时系统,反垃圾系统

通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。

  1. 缓存

将数据直接存放到内存中,性能优于Memcached,数据结构更多样化。

2.3 Redis的特点


  1. 高效性

Redis读取的速度是110000次/s,写的速度是81000次/s

  1. 原子性

Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。

  1. 支持多种数据结构
  • string(字符串)
  • list(列表)
  • hash(哈希)
  • set(集合)
  • zset(有序集合)
  1. 稳定性:持久化,主从复制(集群)

  2. 其他特性:支持过期时间,支持事务,消息订阅。

3 Redis的Linux版单机部署


详见:Redis 的安装与部署

4 Redis 数据类型


整个Reids中所有数据以KV结构形式存在。

  • K:作为唯一标识符,唯一标识一条数据,固定为String类型,写入时指定KV,读取时,根据K读取V
  • V:真正存储的数据,可以有多种类型
    • String、Hash、List、Set、Zset、BitMap、HypeLogLog

理解Redis:类似于Java中的一个Map集合,可以存储多个KV,根据K获取V。

redis当中一共支持五种数据类型,分别是:

  • string字符串
    • KV:【String,String】,类似于Java中Map集合的一条KV
  • list列表
    • 【String,Map集合】:Map集合的嵌套,Map集合中的元素是无序的
  • set集合
    • 【String,List】:有序且可重复
  • hash表
    • 【String,Set】:无序且不重复
  • zset有序集合
    • KV:【String,TreeMap集合】:Value也类似于Map集合,有序的Map集合
    • 类似于List和Set集合特点的合并:有序且不可重复

通过这五种不同的数据类型,可以实现各种不同的功能,也可以应用在各种不同的场景。

在这里插入图片描述

4.1 通用操作


Redis 命令行返回1代表True,返回0代表False。

  1. keys 通配符:列举当前数据库中所有Key

在这里插入图片描述

  1. del K:删除某个KV (del 后可以跟多个key,空格分开)

在这里插入图片描述

  1. exists K:判断某个Key是否存在

在这里插入图片描述

  1. type K:判断这个K对应的V的类型的

在这里插入图片描述

  1. expire K 过期时间:设置某个K的过期时间,一旦到达过期时间,这个K会被自动删除。
    ttl K:查看某个K剩余的存活时间

在这里插入图片描述

  1. select N:切换数据库(N表数据库索引)
  • Redis默认由16个数据:db0 ~ db15,个数可以通过配置文件修改,名称不能改
  • Redis是一层数据存储结构:所有KV直接存储在数据库中
  • 默认进入db0
  1. move K N:将某个Key移动到某个数据库中

在这里插入图片描述

  1. flushdb:清空当前数据库的所有K

  2. flushall:清空所有数据库的所有K

4.2 对字符串string的操作


  1. set K V:给 String 类型的 Value 的进行赋值或者更新

  2. get K:读取 String 类型的 Value 的值

  3. mset K1 V1 K2 V2:用于批量写多个 String 类型的KV

  4. mget K1 K2 K3:用于批量读取 String 类型的 Value

  5. setnx K V:只能用于新增数据,当K不存在时可以进行新增

    应用:构建抢占锁,搭配expire来使用

  6. incr K:用于对数值类型的字符串进行递增,递增1,一般用于做计数器

在这里插入图片描述

  1. incrby K N:指定对数值类型的字符串增长固定的步长

  2. decr K:对数值类型的数据进行递减,递减1

  3. decrby K N:按照指定步长进行递减

  4. incrbyfloat K N:基于浮点数递增

  5. strlen K:统计字符串的长度

  6. getrange K start end:用于截取字符串(start end 索引从0开始,前闭后闭)

4.3 对hash列表的操作


无序,不可重复

  1. hset K k v:用于为某个K添加一个属性

在这里插入图片描述

  1. hget K k:用于获取某个K的某个属性的值

在这里插入图片描述

  1. hmset K k1 v1 k2 v2 …:批量的为某个K赋予新的属性

在这里插入图片描述

  1. hmget K k1 k2 k3…:批量的获取某个K的多个属性的值

  2. hgetall K:获取所有属性的值

  3. hdel K k1 k2 …:删除某个属性

  4. hlen K:统计 K 对应的 Value 总的属性的个数

  5. hexists K k:判断这个K的V中是否包含这个属性

  6. hvals K:获取所有属性的value

4.4 对list列表的操作


有序,可重复

  1. lpush K e1 e2 e3…:将每个元素放到集合的左边,左序放入

在这里插入图片描述

  1. rpush K e1 e2 e3…:将每个元素放到集合的右边,右序放入

在这里插入图片描述

  1. lrange K start end:通过下标的范围来获取元素的数据

注意:从左往右的下标从0开始,从右往左的下标从-1开始,一定是从小的到大的下标。lrange K 0 -1:所有元素。

  1. llen K:统计集合的长度

  2. lpop K:删除左边的一个元素

  3. rpop K:删除右边的一个元素

4.5 对set集合的操作


无序,不可重复

  1. sadd K e1 e2 e3 e4 e5…:用于添加元素到Set集合中

  2. smembers K:用于查看Set集合的所有成员

  3. sismember K e1:判断是否包含这个成员

  4. srem K e:删除其中某个元素

  5. scard K:统计集合长度

  6. sunion K1 K2:取两个集合的并集

  7. sinter K1 K2:取两个集合的交集

4.6 对ZSet的操作


有序,不可重复

  1. zadd K score1 k1 score2 k2…:用于添加元素到Zset集合中

在这里插入图片描述

  1. zrange K start end [withscores]:范围查询

在这里插入图片描述

redis中的数值尽量用整型

在这里插入图片描述

  1. zrevrange K start end [withscores]:倒序查询

在这里插入图片描述

  1. zrem K k1:移除一个元素

  2. zcard K:统计集合长度

  3. zscore K k:获取评分

4.7 对位图BitMaps的操作


在这里插入图片描述

功能:通过一个String对象的存储空间,来构建位图,用每一位0和1来表示状态。

  • Redis中一个String最大支持512M = 2^32,1字节 = 8位
  • 使用时,可以指定每一位对应的值,要么为0,要么为1,默认全部为0
  • 用下标来标记每一位,第一个位的下标为0

举例:统计UV

  • 一个位图中包含很多位,可以用每一个位表示一个用户id
  • 读取数据,发现一个用户id,就将这个用户id对应的那一位改为1
  • 统计整个位图中所有1的个数,就得到了UV

在这里插入图片描述

  1. setbit bit1 位置 0/1:修改某一位的值

在这里插入图片描述

  1. getbit K 位置:查看某一位的值

在这里插入图片描述

注意:start和end表示的是字节,1 字节 = 8 位

  1. bitcount K [start end]:用于统计位图中所有1的个数

在这里插入图片描述

  1. bitop and/or/xor/not bitrs bit1 bit2:用于位图的运算,and/or/not/xor

在这里插入图片描述

在这里插入图片描述

4.8 对HyperLogLog结构的操作


功能:类似于Set集合,用于实现数据的去重

  • 区别:底层实现原理不一样
  • 应用:适合于数据量比较庞大的情况下的使用,存在一定的误差率
  1. pfadd K e1 e2 e3……:用于添加元素

  2. pfcount K:用于统计个数

  3. pfmerge pfrs pf1 pf2…:用于实现集合合并

5 Redis Java API 操作


Redis的使用方式

  • 命令操作Redis,一般用于测试开发阶段
  • 分布式计算或者Java程序读写Redis,一般用于实际生产开发
    • Spark/Flink读写Redis

    • 所有数据库使用Java操作方式整体是类似的

      //todo:1-构建客户端连接对象
      Connection conn = DriverManager.getConnect(url,username,password)
      //todo:2-执行操作:所有操作都在客户端连接对象中:方法
      prep.execute(SQL)
      //todo:3-释放连接
      conn.close
      

Java语言使用 Jedis依赖 来操作Redis数据库。

实现Jedis的客户端连接以及相关操作

public class RedisClientTest {

    //todo:1-构建客户端连接对象
    //单节点连接对象:Jedis
    Jedis jedis = null;

    @Before
    public void getConnection() {
        //方式一:直接构建
        //jedis = new Jedis("node01",6379);
        //方式二:基于连接池来获取连接
        //构建连接池配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(10);//最大连接数
        config.setMaxIdle(5);//连接池中最多可以有多少个空闲的 Jedis 连接
        config.setMinIdle(3);
        //构建连接池对象
        JedisPool jedisPool = new JedisPool(config, "node01", 6379);
        //从池子中获取连接对象
        jedis = jedisPool.getResource();
    }

    //todo:2-执行操作


    @Test
    public void testString() {
        //set/get/incr/exists/expire/setex/ttl
//        jedis.set("s1","hadoop");
//        System.out.println(jedis.get("s1"));
//        jedis.set("s2","5");
//        jedis.incr("s2");
//        System.out.println(jedis.get("s2"));
//        jedis.expire("s2",15);
//        while (true){
//            System.out.println(jedis.ttl("s2"));
//        }
//        System.out.println(jedis.exists("s2"));
//        System.out.println(jedis.exists("s1"));
        //setex = set + expire
        jedis.setex("s2", 10, "hadoop");

    }


    @Test
    public void testHash() {
        //hset/hmset/hget/hgetall/hdel/hlen/hexists
//        jedis.hset("m1","name","zhangsan");
//        System.out.println(jedis.hget("m1","name"));
//        Map<String,String> maps = new HashMap<>();
//        maps.put("age","18");
//        maps.put("phone","110");
//        jedis.hmset("m1",maps);
//        List<String> hmget = jedis.hmget("m1", "name", "age");
//        System.out.println(hmget);
//        System.out.println("=");
//        Map<String, String> m1 = jedis.hgetAll("m1");
//        for(Map.Entry map : m1.entrySet()){
//            System.out.println(map.getKey()+"\t"+map.getValue());
//        }
//        System.out.println("=");
        System.out.println(jedis.hlen("m1"));
        jedis.hdel("m1", "name");
        System.out.println(jedis.hlen("m1"));
        System.out.println(jedis.hexists("m1", "name"));
        System.out.println(jedis.hexists("m1", "age"));
    }

    @Test
    public void testList() {
        //lpush/rpush/lrange/llen/lpop/rpop
        jedis.lpush("list1", "1", "2", "3");
        System.out.println(jedis.lrange("list1", 0, -1));
        jedis.rpush("list1", "4", "5", "6");
        System.out.println(jedis.lrange("list1", 0, -1));
        System.out.println(jedis.llen("list1"));
        jedis.lpop("list1");
        jedis.rpop("list1");
        System.out.println(jedis.lrange("list1", 0, -1));
    }

    @Test
    public void testSet() {
        //sadd/smembers/sismember/scard/srem
        jedis.sadd("set1", "1", "2", "3", "1", "2", "3", "4", "5", "6");
        System.out.println("长度:" + jedis.scard("set1"));
        System.out.println("内容:" + jedis.smembers("set1"));
        System.out.println(jedis.sismember("set1", "1"));
        System.out.println(jedis.sismember("set1", "7"));
        jedis.srem("set1", "2");
        System.out.println("内容:" + jedis.smembers("set1"));

    }

    @Test
    public void testZset() {
        //zadd/zrange/zrevrange/zcard/zrem
        jedis.zadd("zset1", 20.9, "yuwen");
        jedis.zadd("zset1", 10.5, "yinyu");
        jedis.zadd("zset1", 70.9, "shuxue");
        jedis.zadd("zset1", 99.9, "shengwu");
        Set<String> zset1 = jedis.zrange("zset1", 0, -1);
        System.out.println(zset1);
        System.out.println(jedis.zrevrange("zset1", 0, -1));
        System.out.println(jedis.zcard("zset1"));
        jedis.zrem("zset1", "yuwen");
        System.out.println(jedis.zrangeWithScores("zset1", 0, -1));
    }


    //todo:3-释放连接
    @After
    //释放连接
    public void closeConnection() {
        jedis.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值