精华内容
下载资源
问答
  • 常见抽象数据类型
    千次阅读
    2019-03-27 15:48:25

    一、栈

    结构:栈顶、栈底
    特点:后进先出。从栈顶压入栈,从栈顶压出栈

    二、队列

    1、队列

    • 结构
      队头、队尾
    • 特点
      先进先出。从队尾入队列,从队头出队列

    2、双端队列

    结构:队头、队尾
    特点:队头队尾均可入队/出队

    3、优先级队列

    三、树

    1、树

    结构

    • 一种分层的结构,由根节点 + 根节点的子孙节点(子树)组成

    重要概念

    • 节点
      根节点、内部节点、外部节点(叶子节点)
      父亲节点、兄弟节点、孩子节点(左孩子、右孩子)

    • 一对父子节点(u,v)
    • 路径
      指一系列的节点,其中任意两个连续的节点都是一条边
    • 深度
      节点祖先的个数,根节点的深度是0
    • 高度
      从叶子节点往上数的层数,叶子节点的高度是0

    • 同一深度的所有节点位于1层,根节点是第0层

    2、二叉树

    特点:每个节点最多有两个孩子节点(被称为左孩子或右孩子)

    2.1 满二叉树

    特点:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。

    2.2 完全二叉树

    特点:和满二叉树的区别是,它的最后一行可能不是完整的,但绝对是右方的连续部分缺失。即叶子结点只可能在最大的两层出现

    2.2.1 堆(headq)
    • 特点:
      堆是一颗完全二叉树
      除了根节点之外的每个位置,该位置中存储的键值大于等于其父节点的键值

    2、AVL树

    3、伸展树

    4、(2,4)树

    5、红黑树

    四、图

    1、图
    2、无向图
    3、有向图

    五、映射

    1、映射

    每个唯一的关键字(key)都被关联到对应的一个值(value)上。这种关系被称为映射(map)或关联数组。

    2、哈希表

    一种,支持使用键作为索引的结构,语法如M[key]

    2.1 哈希函数

    哈希函数 h :将每个键k映射到[0,N-1]区间内的整数,其中N是哈希表桶数组的容量

    • 哈希码
    • 压缩函数
    2.2 桶数组

    2.3 负载因子

    3、跳跃表

    六、集合

    更多相关内容
  • redis的五种数据类型

    万次阅读 多人点赞 2021-05-15 14:56:27
    (2)Redis是一个key-value存储系统,它支持存储的value类型相对更多,包括string、list、set、zset(sorted set --有序集合)和hash。这些数据结构都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,

    🍅 Java学习路线思维导图:Java学习路线总结(思维导图篇)

    🍅 Java学习路线配套文章:搬砖工逆袭Java架构师

    🍅 Java经典面试题大全:10万字208道Java经典面试题总结(附答案)

    🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪

    🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步 

    🍅 欢迎点赞 👍 收藏 ⭐留言 📝   

    一、百度百科

    1、简介

    (1)Redis(Remote Dictionary Server 远程字段服务)是一个开源的使用ANSI C语言编写、支持网络、科技与内存亦可持久化的日志型、key-value数据库,并提供多种语言的API。

    (2)Redis是一个key-value存储系统,它支持存储的value类型相对更多,包括string、list、set、zset(sorted set --有序集合)和hash。这些数据结构都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,Redis支持各种不同方式的排序。为了保证效率,数据都是缓存在内存中,Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

    (3)Redis提供了java、C/C++、PHP、JavaScript、Perl、Object-C、Python、Ruby、Erlang等客户端,使用很方便。

    (4)Reids支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他服务器的主服务器。这使得Redis可执行单层数复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。

    (5)在我们日常的Java Web开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者是主页访问量瞬间较大的时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。

    2、什么是nosql技术

    为了克服上述问题,java web项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。

    Redis和MongoDB是当前使用最广泛的NoSQL, 而就Redis技术而言,它的性能十分优越,可以支持每秒十几万的读写操作,其性能远超数据库,并且还支持集群、。分布式、主从同步等配置,原则上可以无限扩展,让更多的数据存储在内存中,更让人欣慰的是它还支持一定的事务能力,这保证了高并发的场景下数据的安全和一致性。

    3、Redis为何能解决高并发问题

    1. Redis是基于内存的,内存的读写速度非常快;
    2. Redis是单线程的,省去了很多上下文切换线程的时间;
    3. Redis使用多路复用技术,可以处理并发的连接。非IO内部实现采用epoll,采用了epoll自己实现的简单的事件框架。epoll的读写、关闭、连接都转化为事件,然后利用epoll的多路复用特性,绝不在IO上浪费一点时间。

    Redis高并发总结

    1. Redis是纯内存数据库,一般都是简单存取操作,线程占用的时间很多,时间的花费主要集中在IO上,所以读取速度快;
    2. Redis使用的是非阻塞IO,IO多路复用,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成事件,减少了线程切换时上下文切换和竞争。
    3. Redis采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。
    4. Redis全程使用hash结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如跳表,使用有序的数据结构加快读写的速度。
    5. Redis采用自己实现的事件分离器,效率比较高,内部采用非阻塞的执行方式,吞吐能力比较大。

    4、Redis的优劣势

    (1)优势

    1. 代码更清晰,处理逻辑更简单
    2. 不用考虑各种锁的问题,不存在加锁和释放锁的操作,没有因为可能出现死锁而导致的性能消耗
    3. 不存在多线程切换而消耗CPU

    (2)劣势

    无法发挥多核CPU性能优势,不过可以通过单击开多个Redis实例来完善。

    二、Redis为什么是单线程的

    1、官方答案

    Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络宽带。既然单线程容易实现,而且CPU不会成为瓶颈,那么顺理成章的采用单线程的方案。

    2、我的理解

    (1)不需要各种锁的性能消耗

    Redis的数据结构并不全是key-value形式的,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash中添加或删除一个对象,这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。

    总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁和释放锁的操作,没有因为可能出现的死锁而导致的性能消耗。

    (2)单线程多进程集群方案

    单线程的威力实际上非常强大,每核心效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。

    所以单线程、多进程的集群不失为一个时髦的解决方案。

    (3)CPU消耗

    采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗CPU。

    但是如果CPU称为Redis的瓶颈,或者不想让服务器其它CPU核闲置,那怎么办?

    可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系型数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis进程中就可以了。

    三、Linux中安装Redis

    1、Redis下载

    2、上传、解压

    Redis一般安装在Linux环境下,开启虚拟机,通过xftp将redis压缩包上传到Linux服务器,并进行解压。

    修改redis.conf配置文件,使其在后台启动

    四、Redis在Java Web中的应用

    Redis 在 Java Web 主要有两个应用场景:

    • 存储缓存用的数据
    • 需要高速读写的场合

    1、存储缓存用的数据 

    在日常对数据库的访问中,读操作的次数远超写操作,比例大概在 1:9 到 3:7,所以需要读的可能性是比写的可能大得多的。当我们使用SQL语句去数据库进行读写操作时,数据库就会去磁盘把对应的数据索引取回来,这是一个相对较慢的过程。 

    如果放在Redis中,也就是放在内存中,让服务器直接读取内存中的数据,那么速度就会快很多,并且会极大减少数据库的压力,但是使用内存进行数据存储开销也是比较大的,限于成本的原因,一般我们只是使用Redis存储一些常用的和主要的数据,比如用户登录信息等。

    一般而言在使用 Redis 进行存储的时候,我们需要从以下几个方面来考虑:

    (1)业务数据常用吗?使用率如何?

    如果使用率较低,就没必要写入缓存。

    (2)该业务是读操作多,还是写操作多?

    如果写操作多,频繁需要写入数据库,也没必要使用缓存。

    (3)业务数据大小如何?

    如果要存储几百兆字节的文件,会给缓存带来很大的压力,这样也没必要。

    在考虑了这些问题之后,如果觉得有必要使用缓存,那么就使用它!

    从上图我们可以知道以下两点:

    (1)当第一次读取数据的时候,读取Redis的数据就会失败,此时就会触发程序读取数据库,把数据读取出来,并且写入Redis中

    (2)当第二次以及以后需要读取数据时,就会直接读取Redis,读取数据后就结束了流程,这样速度大大提高了。

    从上面的分析可以知道,读操作的可能性是远大于写操作的,所以使用 Redis 来处理日常中需要经常读取的数据,速度提升是显而易见的,同时也降低了对数据库的依赖,使得数据库的压力大大减少。

    分析了读操作的逻辑,下面我们来看看写操作流程:

    从流程可以看出,更新或者写入的操作,需要多个 Redis 的操作,如果业务数据写次数远大于读次数那么就没有必要使用 Redis。

    2、高速读写场合

    在如今的互联网中,越来越多的存在高并发的情况,比如天猫双11、抢红包、抢演唱会门票等,这些场合都是在某一个瞬间或者是某一个短暂的时刻有成千上万的请求到达服务器,如果单纯的使用数据库来进行处理,就算不崩,也会很慢的,轻则造成用户体验极差用户量流水,重则数据库瘫痪,服务宕机,而这样的场合都是不允许的!

    所以我们需要使用 Redis 来应对这样的高并发需求的场合,我们先来看看一次请求操作的流程:

    我们来进一步阐述这个过程:

    (1)当一个请求到达服务器时,只是把业务数据在Redis上进行读写,而没有对数据库进行任何的操作,这样就能大大提高读写的速度,从而满足高速相应的需求。

    (2)但是这些缓存的数据仍然需要持久化,也就是存入数据库之中,所以在一个请求操作完Redis的读写之后,会去判断该高速读写的业务是否结束,这个判断通常会在秒杀商品为0,红包金额为0时成立,如果不成立,则不会操作数据库;如果成立,则触发事件将Redis的缓存的数据以批量的形式一次性写入数据库,从而完成持久化的工作。

    五、Redis代码实例

    1、Java整合Redis

    (1)导入pom

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

    (2)编写Java主方法

    调用Redis中的ping方法,惊现异常:

    开始的时候以为是防火墙的问题,后来通过查看redis状态发现IP地址不对,不应该是127.0.0.1

    修改redis.conf

    注意:需要注意的是在修改redis.conf时,①注掉bind 127.0.0.1;②需要将本机访问保护模式设置为no;③此时可以配置多个ip

    (3)再次执行主方法,执行成功!

    2、五大数据类型代码实例

    package com.guor.redis;
     
    import redis.clients.jedis.Jedis;
     
    import java.util.List;
    import java.util.Set;
     
    public class JedisTest01 {
        public static void main(String[] args) {
            test05();
        }
     
        private static void test01(){
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            String value = jedis.ping();
            System.out.println(value);
            //添加
            jedis.set("name","GooReey");
            //获取
            String name = jedis.get("name");
            System.out.println(name);
     
            jedis.set("age","30");
            jedis.set("city","dalian");
            //获取全部的key
            Set<String> keys = jedis.keys("*");
            for(String key : keys){
                System.out.println(key+" --> "+jedis.get(key));
            }
     
            //加入多个key和value
            jedis.mset("name1","zs","name2","ls","name3","ww");
            List<String> mget = jedis.mget("name1", "name2");
            System.out.println(mget);//[zs, ls]
        }
     
        //list
        private static void test02(){
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            jedis.lpush("key1","01","02","03");
            List<String> values = jedis.lrange("key1",0,-1);
            System.out.println(values);//[03, 02, 01]
        }
     
        //set
        private static void test03(){
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            jedis.sadd("username","zs","ls","ww");
            Set<String> names = jedis.smembers("username");
            System.out.println(names);//[ww, zs, ls]
        }
     
        //hash
        private static void test04(){
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            jedis.hset("users","age", "20");
            String hget = jedis.hget("users","age");
            System.out.println(hget);
        }
     
        //zset
        private static void test05(){
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            jedis.zadd("china",100d,"shanghai");
            Set<String> names = jedis.zrange("china",0,-1);
            System.out.println(names);//[shanghai]
        }
    }

    3、手机验证码功能代码实例

    package com.guor.redis;
     
    import redis.clients.jedis.Jedis;
     
    import java.util.Random;
     
    public class PhoneCode {
        public static void main(String[] args) {
            verifyCode("10086");//795258
            getRedisCode("10086","795258");//success.
        }
     
        //1、生成6位数字验证码
        public static String getCode(){
            Random random = new Random();
            String code = "";
            for (int i = 0; i < 6; i++) {
                int rand = random.nextInt(10);
                code += rand;
            }
            return code;//849130
        }
     
        //2、每个手机每天只能发送三次,验证码放到redis中,设置过期时间
        public static void verifyCode(String phone){
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            //拼接key
            //手机发送次数key
            String countKey = "VerifyCode" + phone + ":count";
            //验证码key
            String codeKey = "VerifyCode" + phone + ":code";
            //每个手机每天只能发送三次
            String count = jedis.get(countKey);
            if(count == null){
                //设置过期时间
                jedis.setex(countKey,24*60*60,"1");
            }else if(Integer.parseInt(count)<=2){
                //发送次数+1
                jedis.incr(countKey);
            }else if(Integer.parseInt(count)>2){
                System.out.println("今天的发送次数已经超过三次");
                jedis.close();
            }
     
            String vCode = getCode();
            jedis.setex(codeKey,120,vCode);
            jedis.close();
        }
     
        //3、验证码校验
        public static void getRedisCode(String phone, String code){
            //从redis中获取验证码
            Jedis jedis = new Jedis("192.168.194.131", 6379);
            //验证码key
            String codeKey = "VerifyCode" + phone + ":code";
            String redisCode = jedis.get(codeKey);
            if(redisCode.equals(code)){
                System.out.println("success.");
            }else{
                System.out.println("error");
            }
            jedis.close();
        }
    }

    当超过三次时: 

    4、SpringBoot整合Redis

    (1)建工程,引入pom

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.guor</groupId>
        <artifactId>redisspringboot</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>redisspringboot</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>1.8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
     
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
     
            <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <version>2.4.5</version>
            </dependency>
     
            <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
                <version>2.9.0</version>
            </dependency>
     
        </dependencies>
     
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
     
    </project>

    (2)配置类

    application.properties

    # Redis数据库索引(默认为0)
    spring.redis.database=0
    # Redis服务器地址
    spring.redis.host=192.168.194.131
    # Redis服务器连接端口
    spring.redis.port=6379
    # Redis服务器连接密码(默认为空)
    spring.redis.password=
    # 连接池最大连接数(使用负值表示没有限制)
    spring.redis.jedis.pool.max-active=20
    # 连接池最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.jedis.pool.max-wait=-1
    # 连接池中的最大空闲连接
    spring.redis.jedis.pool.max-idle=10
    # 连接池中的最小空闲连接
    spring.redis.jedis.pool.min-idle=0
    # 连接超时时间(毫秒)
    spring.redis.timeout=1000

    RedisConfig

    package com.guor.redisspringboot.config;
     
    import com.fasterxml.jackson.annotation.JsonAutoDetect;
    import com.fasterxml.jackson.annotation.JsonTypeInfo;
    import com.fasterxml.jackson.annotation.PropertyAccessor;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheManager;
    import org.springframework.data.redis.cache.RedisCacheWriter;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.*;
     
    import java.time.Duration;
     
    @EnableCaching
    @Configuration
    public class RedisConfig {
        @Bean
        public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            template.setConnectionFactory(factory);
     
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    //        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
            jackson2JsonRedisSerializer.setObjectMapper(om);
     
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            // key采用String的序列化方式
            template.setKeySerializer(stringRedisSerializer);
            // hash的key也采用String的序列化方式
            template.setHashKeySerializer(stringRedisSerializer);
            // value序列化方式采用jackson
            template.setValueSerializer(jackson2JsonRedisSerializer);
            // hash的value序列化方式采用jackson
            template.setHashValueSerializer(jackson2JsonRedisSerializer);
            template.afterPropertiesSet();
            return template;
        }
     
        /**
         * 基于SpringBoot2 对 RedisCacheManager 的自定义配置
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
            //初始化一个RedisCacheWriter
            RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
            //设置CacheManager的值序列化方式为json序列化
            RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
            RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer);
            RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
     
            //设置默认超过时期是1天
            defaultCacheConfig.entryTtl(Duration.ofDays(1));
            //初始化RedisCacheManager
            return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
        }
    }

    (3)控制类测试

    package com.guor.redisspringboot.controller;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    @RestController
    @RequestMapping("/redisTest")
    public class RedisTestController {
     
        @Autowired
        private RedisTemplate redisTemplate;
     
        @GetMapping
        public String getRedis(){
            redisTemplate.opsForValue().set("name","zs");
            String name = (String) redisTemplate.opsForValue().get("name");
            return name;
        }
    }

    (4)测试

    六、Redis事务

    众所周知,事务是指“一个完整的动作,要么全部执行,要么什么也没有做”。

    在聊redis事务处理之前,要先和大家介绍四个redis指令,即multi、exec、discard、watch。这四个指令构成了redis事务处理的基础。

    1.multi用来组装一个事务;
    2.exec用来执行一个事务;
    3.discard用来取消一个事务;
    4.watch用来监视一些key,一旦这些key在事务执行之前被改变,则取消事务的执行。

    redis> multi 
    OK
    redis> INCR id
    QUEUED
    redis> INCR id
    QUEUED
    redis> INCR id
    QUEUED
    redis> exec
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3

    我们在用multi组装事务时,每一个命令都会进入内存中缓存起来,QUEUED表示缓存成功,在exec时,这些被QUEUED的命令都会被组装成一个事务来执行。

    对于事务的执行来说,如果redis开启了AOF持久化的话,那么一旦事务被成功执行,事务中的命令就会通过write命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,那么就可能出现只有部分命令进行了AOF持久化,这时AOF文件就会出现不完整的情况,这时,我们可以使用redis-check-aof工具来修复这一问题,这个工具会将AOF文件中不完整的信息移除,确保AOF文件完整可用。

    有关事务,大家经常会遇到的是两类错误:

    1.调用EXEC之前的错误
    2.调用EXEC之后的错误

    “调用EXEC之前的错误”,有可能是由于语法有误导致的,也可能时由于内存不足导致的。只要出现某个命令无法成功写入缓冲队列的情况,redis都会进行记录,在客户端调用EXEC时,redis会拒绝执行这一事务。(这时2.6.5版本之后的策略。在2.6.5之前的版本中,redis会忽略那些入队失败的命令,只执行那些入队成功的命令)。

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> hello world //错误指令
    (error) ERR unknown command 'hello world'
    127.0.0.1:6379> ping
    QUEUED
    127.0.0.1:6379> exec
    (error) EXECABORT Transaction discarded because of previous errors.

    而对于“调用EXEC之后的错误”,redis则采取了完全不同的策略,即redis不会理睬这些错误,而是继续向下执行事务中的其他命令。这是因为,对于应用层面的错误,并不是redis自身需要考虑和处理的问题,所以一个事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行。我们也来看一个例子:

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set age 23
    QUEUED
    //age不是集合,所以如下是一条明显错误的指令
    127.0.0.1:6379> sadd age 15 
    QUEUED
    127.0.0.1:6379> set age 29
    QUEUED
    127.0.0.1:6379> exec //执行事务时,redis不会理睬第2条指令执行错误
    1) OK
    2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
    3) OK
    127.0.0.1:6379> get age
    "29" //可以看出第3条指令被成功执行了

    好了,我们来说说最后一个指令“watch”,这是一个很好用的指令,它可以帮我们实现类似于“乐观锁”的效果,即CAS(check and set)。

    watch本身的作用是“监视key是否被改动过”,而且支持同时监视多个key,只要还没真正触发事务,watch都会尽职尽责的监视,一旦发现某个key被修改了,在执行exec时就会返回nil,表示事务无法触发。

    127.0.0.1:6379> set age 23
    OK
    127.0.0.1:6379> watch age //开始监视age
    OK
    127.0.0.1:6379> set age 24 //在EXEC之前,age的值被修改了
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set age 25
    QUEUED
    127.0.0.1:6379> get age
    QUEUED
    127.0.0.1:6379> exec //触发EXEC
    (nil) //事务无法被执行

    七、Redis持久化的两种方式

    redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。

    RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;

    AOF,则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

    其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。

    如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库,就像memcache一样。


    1、RDB

    RDB方式,是将redis某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

    redis在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。

    对于RDB方式,redis会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何IO操作的,这样就确保了redis极高的性能。

    如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。

    虽然RDB有不少优点,但它的缺点也是不容忽视的。如果你对数据的完整性非常敏感,那么RDB方式就不太适合你,因为即使你每5分钟都持久化一次,当redis故障时,仍然会有近5分钟的数据丢失。所以,redis还提供了另一种持久化方式,那就是AOF。


    2、AOF

    AOF,英文是Append Only File,即只允许追加不允许改写的文件。

    如前面介绍的,AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。

    我们通过配置redis.conf中的appendonly yes就可以打开AOF功能。如果有写操作(如SET等),redis就会被追加到AOF文件的末尾。

    默认的AOF持久化策略是每秒钟fsync一次(fsync是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis仍然可以保持很好的处理性能,即使redis故障,也只会丢失最近1秒钟的数据。

    如果在追加日志时,恰好遇到磁盘空间满、inode满或断电等情况导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志修复。

    因为采用了追加方式,如果不做任何处理的话,AOF文件会变得越来越大,为此,redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了100次INCR指令,在AOF文件中就要存储100条指令,但这明显是很低效的,完全可以把这100条指令合并成一条SET指令,这就是重写机制的原理。

    在进行AOF重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响AOF文件的可用性,这点大家可以放心。

    AOF方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作redis时,不小心执行了FLUSHALL,导致redis内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件还没有被重写(rewrite),我们就可以用最快的速度暂停redis并编辑AOF文件,将最后一行的FLUSHALL命令删除,然后重启redis,就可以恢复redis的所有数据到FLUSHALL之前的状态了。是不是很神奇,这就是AOF持久化方式的好处之一。但是如果AOF文件已经被重写了,那就无法通过这种方法来恢复数据了。

    虽然优点多多,但AOF方式也同样存在缺陷,比如在同样数据规模的情况下,AOF文件要比RDB文件的体积大。而且,AOF方式的恢复速度也要慢于RDB方式。

    如果你直接执行BGREWRITEAOF命令,那么redis会生成一个全新的AOF文件,其中便包括了可以恢复现有数据的最少的命令集。

    如果运气比较差,AOF文件出现了被写坏的情况,也不必过分担忧,redis并不会贸然加载这个有问题的AOF文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:

    1.备份被写坏的AOF文件
    2.运行redis-check-aof –fix进行修复
    3.用diff -u来看下两个文件的差异,确认问题点
    4.重启redis,加载修复后的AOF文件







    3、AOF重写

    AOF重写的内部运行原理,我们有必要了解一下。

    在重写即将开始之际,redis会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。

    与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。

    当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中。

    当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中了。

    4、如何选择RDB和AOF

    对于我们应该选择RDB还是AOF,官方的建议是两个同时使用。这样可以提供更可靠的持久化方案。


    八、Redis集群

    1、主从同步简介

    像MySQL一样,redis是支持主从同步的,而且也支持一主多从以及多级从结构。

    主从结构,一是为了纯粹的冗余备份,二是为了提升读性能,比如很消耗性能的SORT就可以由从服务器来承担。

    redis的主从同步是异步进行的,这意味着主从同步不会影响主逻辑,也不会降低redis的处理性能。

    主从架构中,可以考虑关闭主服务器的数据持久化功能,只让从服务器进行持久化,这样可以提高主服务器的处理性能。

    在主从架构中,从服务器通常被设置为只读模式,这样可以避免从服务器的数据被误修改。但是从服务器仍然可以接受CONFIG等指令,所以还是不应该将从服务器直接暴露到不安全的网络环境中。如果必须如此,那可以考虑给重要指令进行重命名,来避免命令被外人误执行。

    2、主从同步原理

    从服务器会向主服务器发出SYNC指令,当主服务器接到此命令后,就会调用BGSAVE指令来创建一个子进程专门进行数据持久化工作,也就是将主服务器的数据写入RDB文件中。在数据持久化期间,主服务器将执行的写指令都缓存在内存中。

    在BGSAVE指令执行完成后,主服务器会将持久化好的RDB文件发送给从服务器,从服务器接到此文件后会将其存储到磁盘上,然后再将其读取到内存中。这个动作完成后,主服务器会将这段时间缓存的写指令再以redis协议的格式发送给从服务器。

    另外,要说的一点是,即使有多个从服务器同时发来SYNC指令,主服务器也只会执行一次BGSAVE,然后把持久化好的RDB文件发给多个下游。在redis2.8版本之前,如果从服务器与主服务器因某些原因断开连接的话,都会进行一次主从之间的全量的数据同步;而在2.8版本之后,redis支持了效率更高的增量同步策略,这大大降低了连接断开的恢复成本。

    主服务器会在内存中维护一个缓冲区,缓冲区中存储着将要发给从服务器的内容。从服务器在与主服务器出现网络瞬断之后,从服务器会尝试再次与主服务器连接,一旦连接成功,从服务器就会把“希望同步的主服务器ID”和“希望请求的数据的偏移位置(replication offset)”发送出去。主服务器接收到这样的同步请求后,首先会验证主服务器ID是否和自己的ID匹配,其次会检查“请求的偏移位置”是否存在于自己的缓冲区中,如果两者都满足的话,主服务器就会向从服务器发送增量内容。

    增量同步功能,需要服务器端支持全新的PSYNC指令。这个指令,只有在redis-2.8之后才具有。

    九、redis.conf配置文件简介

    【Redis 4】配置文件redis.conf简介

    十、Redis常见问题

    1、缓存穿透

    每次针对某key的请求在缓存中获取不到,请求都会压到数据库,从而可能压垮数据库。



    2、缓存击穿

    某key对应的数据存在,但在Redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期,一般都会从数据库中加载数据并设置到缓存中,这个时候大并发的请求可能会瞬间把数据库压垮。

    3、缓存雪崩

    某key对应的数据存在,但在Redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期,一般都会从数据库中加载数据并设置到缓存中,这个时候大并发的请求可能会瞬间把数据库压垮。

    缓存雪崩和缓存击穿的区别就在于是多个key还是某一个key。

    4、分布式锁

    使用Redis实现分布式锁

    redis命令:set users 10 nx ex 12   原子性命令

    //使用uuid,解决锁释放的问题
    @GetMapping
    public void testLock() throws InterruptedException {
        String uuid = UUID.randomUUID().toString();
        Boolean b_lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 10, TimeUnit.SECONDS);
        if(b_lock){
            Object value = redisTemplate.opsForValue().get("num");
            if(StringUtils.isEmpty(value)){
                return;
            }
            int num = Integer.parseInt(value + "");
            redisTemplate.opsForValue().set("num",++num);
            Object lockUUID = redisTemplate.opsForValue().get("lock");
            if(uuid.equals(lockUUID.toString())){
                redisTemplate.delete("lock");
            }
        }else{
            Thread.sleep(100);
            testLock();
        }
    }

    备注:可以通过lua脚本,保证分布式锁的原子性。

    🍅 Java学习路线思维导图:Java学习路线总结(思维导图篇)

    🍅 Java学习路线配套文章:搬砖工逆袭Java架构师

    🍅 Java经典面试题大全:10万字208道Java经典面试题总结(附答案)

    🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者💪

    🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步 

    🍅 欢迎点赞 👍 收藏 ⭐留言 📝   

    添加微信,备注1024,赠送Java学习路线思维导图 

    展开全文
  • redis五种数据类型及其常见操作

    千次阅读 2020-02-26 14:45:37
    redis五种数据类型及其常见操作 Redis支持5种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。 1、string string是 redis 最基本的类型,你可以理解成与 ...

    redis五种数据类型及其常见操作

    Redis支持5种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

    1、string

     string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。value其实不仅是String,也可以是数字。string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

      常用命令:get、set、incr、decr、mget等。

      应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类,即可以完全实现目前 Memcached 的功能,并且效率更高。还可以享受Redis的定时持久化,操作日志及 Replication等功能。除了提供与 Memcached 一样的get、set、incr、decr 等操作外,Redis还提供了下面一些操作: 

    • 获取字符串长度
    • 往字符串append内容
    • 设置和获取字符串的某一段内容
    • 设置及获取字符串的某一位(bit)
    • 批量设置一系列字符串的内容

      使用场景:常规key-value缓存应用。常规计数: 微博数, 粉丝数。

    string
    增:
    127.0.0.1:6379> set name runoob             #批量增加:mset 
    OK
    
    查:
    127.0.0.1:6379> get name
    "runoob"
    
    改:
    127.0.0.1:6379> set name tom            #直接覆盖
    OK
    
    删:
    127.0.0.1:6379> del name
    (integer) 1
    

    2、hash

    hash 是一个键值(key => value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象

      常用命令:hget,hset,hgetall 等。

      应用场景:我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:

        用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

        第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

        第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

        那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,如下图:

        也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题,很好的解决了问题。

        这里同时需要注意,Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

      使用场景:存储部分变更数据,如用户信息等。

    hash

    hgetall key     #不需要具体字段,直接获取整个hash值

    增:

    127.0.0.1:6379> hset 001 name zsq          #设置多个属性:hmset  001 name zsq age 18
    (integer) 1

    查:

    127.0.0.1:6379> hget 001 name
    "zsq"

    改:

    127.0.0.1:6379> hset 001 name zcf           #直接覆盖
    (integer) 0

    删:

    127.0.0.1:6379> del 001
    (integer) 1

            删掉hash的一个属性:

            127.0.0.1:6379> hdel  001 age
             (integer) 1 

     

    3、list

    list 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

      常用命令:lpush(添加左边元素),rpush,lpop(移除左边第一个元素),rpop,lrange(获取列表片段,LRANGE key start stop)等。

      应用场景:Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。

        List 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用List结构,我们可以轻松地实现最新消息排行等功能。List的另一个应用就是消息队列,
    可以利用List的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作List中某一段的api,你可以直接查询,删除List中某一段的元素。

      实现方式:Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

      Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。 获取越接近两端的元素速度越快,但通过索引访问时会比较慢。

    使用场景:

      消息队列系统:使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。比如:将Redis用作日志收集器,实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。

    list

    增:

    127.0.0.1:6379> lpush list aa bb cc dd                       #lpush/rpush list XXX
    (integer) 4

    查:

    127.0.0.1:6379> LRANGE list 0 -1                         #查询整个列表
    1) "dd"
    2) "cc"
    3) "bb"
    4) "aa"

    改:

    127.0.0.1:6379> lset list 0 00                 #修改需要指定到对应下标
    OK

    删:

    127.0.0.1:6379> del list                      #删除整个列表
    (integer) 1

    127.0.0.1:6379> lrem list 1 aa            #从列表list左边开始删除1个aa的值
    (integer) 1

    解释:

    LREM key count value

    根据参数 count 的值,移除列表中与参数 value 相等的元素。

    count 的值可以是以下几种:

    count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。
    count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。
    count = 0 : 移除表中所有与 value 相等的值。

    4、set

    set是string类型的无序集合。集合是通过hashtable实现的,概念和数学中个的集合基本类似,可以交集,并集,差集等等,set中的元素是没有顺序的。所以添加,删除,查找的复杂度都是O(1)。

      sadd 命令:添加一个 string 元素到 key 对应的 set 集合中,成功返回1,如果元素已经在集合中返回 0,如果 key 对应的 set 不存在则返回错误。

      常用命令:sadd,spop,smembers,sunion 等。

      应用场景:Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

      Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis提供的Set数据结构,可以存储一些集合性的数据。

      案例:在微博中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。

      实现方式: set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

    set

    增:

    127.0.0.1:6379> sadd ss aa bb cc
    (integer) 3

    删:

    127.0.0.1:6379> SREM ss bb
    (integer) 1

    查:

    127.0.0.1:6379> SMEMBERS ss
    1) "bb"
    2) "cc"
    3) "aa"

    5、zset

     zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

      zadd 命令:添加元素到集合,元素在集合中存在则更新对应score。

      常用命令:zadd,zrange,zrem,zcard等

      使用场景:Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。和Set相比,Sorted Set关联了一个double类型权重参数score,使得集合中的元素能够按score进行有序排列,redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。比如一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。

      实现方式:Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

    zset

    增:

    127.0.0.1:6379> zadd zz 1 zz1
    (integer) 1
    127.0.0.1:6379> zadd zz 2 zz2
    (integer) 1
    127.0.0.1:6379> zadd zz 3 zz3
    (integer) 1

    查:

    127.0.0.1:6379> ZRANGE zz 0 -1
    1) "zz1"
    2) "zz2"
    3) "zz3"

    删:

    127.0.0.1:6379> ZREM zz zz2
    (integer) 1

    集合中元素数量:

    127.0.0.1:6379> ZCARD zz
    (integer) 2

    参考:https://www.cnblogs.com/jasonZh/p/9513948.html

     

    展开全文
  • redis五种基本数据类型

    千次阅读 2020-07-14 12:58:18
    是redis中最基本的数据类型,一个key对应一个value。 String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。 使用:get 、 set 、 del 、 incr、 decr 等...


    在这里插入图片描述

    对redis来说,所有的key(键)都是字符串。

    1.String 字符串类型

    是redis中最基本的数据类型,一个key对应一个value。

    String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。
    使用:get 、 set 、 del 、 incr、 decr 等

    127.0.0.1:6379> set hello world
    OK
    127.0.0.1:6379> get hello
    "world"
    127.0.0.1:6379> del hello
    (integer) 1
    127.0.0.1:6379> get hello
    (nil)
    127.0.0.1:6379> get counter
    "2"
    127.0.0.1:6379> incr counter
    (integer) 3
    127.0.0.1:6379> get counter
    "3"
    127.0.0.1:6379> incrby counter 100
    (integer) 103
    127.0.0.1:6379> get counter
    "103"
    127.0.0.1:6379> decr counter
    (integer) 102
    127.0.0.1:6379> get counter
    "102"
    

    实战场景:

    1.缓存: 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。

    2.计数器:redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。

    3.session:常见方案spring session + redis实现session共享,

    2.Hash (哈希)

    是一个Mapmap,指值本身又是一种键值对结构,如 value={{field1,value1},…fieldN,valueN}}

    在这里插入图片描述

    127.0.0.1:6379> hset user name1 hao
    (integer) 1
    127.0.0.1:6379> hset user email1 hao@163.com
    (integer) 1
    127.0.0.1:6379> hgetall user
    1) "name1"
    2) "hao"
    3) "email1"
    4) "hao@163.com"
    127.0.0.1:6379> hget user user
    (nil)
    127.0.0.1:6379> hget user name1
    "hao"
    127.0.0.1:6379> hset user name2 xiaohao
    (integer) 1
    127.0.0.1:6379> hset user email2 xiaohao@163.com
    (integer) 1
    127.0.0.1:6379> hgetall user
    1) "name1"
    2) "hao"
    3) "email1"
    4) "hao@163.com"
    5) "name2"
    6) "xiaohao"
    7) "email2"
    8) "xiaohao@163.com"
    

    实战场景:

    1.缓存: 能直观,相比string更节省空间,的维护缓存信息,如用户信息,视频信息等。

    3.链表

    List 说白了就是链表(redis 使用双端链表实现的 List),是有序的,value可以重复,可以通过下标取出对应的value值,左右两边都能进行插入和删除数据。
    在这里插入图片描述
    使用列表的技巧

    • lpush+lpop=Stack(栈)
    • lpush+rpop=Queue(队列)
    • lpush+ltrim=Capped Collection(有限集合)
    • lpush+brpop=Message Queue(消息队列)
    127.0.0.1:6379> lpush mylist 1 2 ll ls mem
    (integer) 5
    127.0.0.1:6379> lrange mylist 0 -1
    1) "mem"
    2) "ls"
    3) "ll"
    4) "2"
    5) "1"
    127.0.0.1:6379>
    

    实战场景:

    1.timeline:例如微博的时间轴,有人发布微博,用lpush加入时间轴,展示新的列表信息。

    4.Set 集合

    集合类型也是用来保存多个字符串的元素,但和列表不同的是集合中 1. 不允许有重复的元素,2.集合中的元素是无序的,不能通过索引下标获取元素,3.支持集合间的操作,可以取多个集合取交集、并集、差集。
    在这里插入图片描述
    使用:命令都是以s开头的 sset 、srem、scard、smembers、sismember

    127.0.0.1:6379> sadd myset hao hao1 xiaohao hao
    (integer) 3
    127.0.0.1:6379> SMEMBERS myset
    1) "xiaohao"
    2) "hao1"
    3) "hao"
    127.0.0.1:6379> SISMEMBER myset hao
    (integer) 1
    

    实战场景;

    1.标签(tag),给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。

    2.点赞,或点踩,收藏等,可以放到set中实现

    5.zset 有序集合

    有序集合和集合有着必然的联系,保留了集合不能有重复成员的特性,区别是,有序集合中的元素是可以排序的,它给每个元素设置一个分数,作为排序的依据。

    (有序集合中的元素不可以重复,但是score 分数 可以重复,就和一个班里的同学学号不能重复,但考试成绩可以相同)。
    在这里插入图片描述
    使用: 有序集合的命令都是 以 z 开头 zadd 、 zrange、 zscore

    127.0.0.1:6379> zadd myscoreset 100 hao 90 xiaohao
    (integer) 2
    127.0.0.1:6379> ZRANGE myscoreset 0 -1
    1) "xiaohao"
    2) "hao"
    127.0.0.1:6379> ZSCORE myscoreset hao
    "100"
    

    实战场景:

    1.排行榜:有序集合经典使用场景。例如小说视频等网站需要对用户上传的小说视频做排行榜,榜单可以按照用户关注数,更新时间,字数等打分,做排行。

    展开全文
  • redis大常用数据类型

    千次阅读 2020-08-25 12:18:27
    下面是我总结的大数据类常用的api,按照使用频率从前往后排列。 1.String类型 String是redis最基本的类型,在redis中,一个key对应一个value。...应用场景:String是最常用的一种数据类型,普通的
  • 最常用的三种数据类型

    万次阅读 2019-08-09 20:47:27
    在python中,最常用的数据类型有:整型,字符串,浮点型 一.数据类型 1.整型 int() 整型就是整数,跟我们现实生活中的数学中的整数定义是一样的,是正整数,负整数和零的合称,是没有小数点的数字。 例如:a=...
  • Redis redis五种数据类型和使用场景

    千次阅读 2019-05-03 16:00:29
    丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行(简单的事务)。 ...
  • Python语言包括九基本的数据类型,我们把它分为以下三类。 数字类型 整数、浮点数、复数 字节类型 字符串、字节串 组合类型 集合、元组、列表、字典 一、数字类型 1 整数类型 与数学中的整数...
  • 五种常见的计算机病毒种类哪些

    万次阅读 2021-07-14 00:38:38
    五种常见的计算机病毒种类系统病毒、蠕虫病毒、木马病毒、脚本病毒、宏病毒。计算机病毒(Computer Virus)是编制者在计算机程序中插入的破坏计算机功能或者数据的代码,能影响计算机使用,能自我复制的一组计算机...
  • redis常见数据类型 及其使用场景 计数器 排行榜
  • ORACLE常见数据类型

    万次阅读 2018-05-30 14:04:30
    1、字符类型• CHAR:一个定长字符串,当位数不足自动用空格填充来达到其最大长度。如非NULL的CHAR(12)总是包含12字节信息。CHAR字段最多可以存储2,000字节的 信息。• VARCHAR2:目前这也是VARCHAR 的同义词。这是...
  • 一、redis的五种数据类型 redis作为目前最流行的Key-Value类型的内存数据库,对于数据库的操作都在内存中进行,并可定期的将数据异步的持久化到磁盘之上。由于是纯内存的操作,因此它的性能比普通的关系型数据库高...
  • 常见的数据库有哪

    万次阅读 2020-06-01 10:58:29
    SQL(StructuredQueryLanguage,结构化查询语言)是一数据库查询语言和程序设计语言,主要用于管理数据库中的数据,如存取数据、查询数据、更新数据等。 SQL是IBM公司于1975—1979年之间开发出来的,在20世纪随着...
  • Python基本数据类型有哪些

    千次阅读 2020-04-23 17:46:20
    1.基本数据类型 1.数字类型:整型(int),浮点型(float),复数类型(complex) 2.字符串类型:str 3.逻辑类型:bool True False 4.列表类型:list [ ] 有序可修改 5.元组类型:tuple () 有序不可修改 6.集合类型:set {...
  • ORACLE常见数据类型详解

    万次阅读 2017-12-05 09:55:41
    1、字符类型 • CHAR:一个定长字符串,当位数不足自动用空格填充来达到其最大长度。如非NULL的CHAR(12)总是包含12字节信息。CHAR字段最多可以存储2,000字节的 信息。 • VARCHAR2:目前这也是VARCHAR 的同义词。...
  • 五种常见的基带数字编码方式

    千次阅读 2021-07-21 00:43:07
    基带数字通信系统的任务是传输数字信息,数字信息可能来自数据终端设备的原始数据信号,也可能来自模拟信号经数字化处理后的脉冲编码信号。...关于基带数字信号表示,下面一些常见的细节:对于传输数字信号...
  • Redis的五种数据类型及方法

    千次阅读 2019-10-31 23:09:48
    字符串类型是Redis中最为基础的数据存储类型,是一个由字节组成的序列,他在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据货Json对象描述信息等,是标准的key-value,一般来存...
  • 近年来,在科学技术急速发展的背景下,当代医疗正在变得越来越智慧,东软医疗所推出的MDaaS,即医疗设备和医疗影像数据服务,可以提供各种创新医疗数据服务和解决方案,帮助医生提高工作效率,同时也可以帮助改善...
  • Java中常见五种异常

    千次阅读 2021-03-01 07:19:24
    1.ClassCastException(类转换异常)数据类型转换错误,比如个String temp="abc";如果设为(int)temp就会报错了,因为它们类型不一样,但是设为(object)temp就可以,因为object是它们的父类2....
  • 2.Redis五种数据类型及使用场景

    万次阅读 2021-08-07 09:52:49
    通过使用场景,带大家快速掌握Redis五种数据类型。string (字符串)、list (列表)、set (集合)、hash (哈希) 和 zset (有序集合)。
  • JavaScript哪些数据类型和常用方法

    千次阅读 2019-01-19 22:58:42
    这里是修真院前端小课堂,每篇分享文从 【背景介绍】【知识剖析】【常见...【 JavaScript哪些数据类型和常用方法】 1.背景介绍: JavaScript:是脚本语言。是一轻量级的编程语言。它是可插入HTML页面的编程代...
  • Python 基础数据类型-数值类型

    千次阅读 2021-01-13 00:00:38
    Python 基础数据类型-数值类型为什么会有数据类型?[了解]更好分配管理内存方便统一管理更贴近人类分类管理习惯数据类型种类 [熟悉]数值类型:int、bool、float、complex序列类型:不可变:str、tuple、bytes 可变:...
  • SQL Server 常见数据类型

    千次阅读 多人点赞 2019-01-17 19:44:49
    数据类型 描述 char(n) 固定长度的字符串。最多 8,000 个字符。 -性能好。 varchar(n) 可变长度的字符串。最多 8,000 个字符。 -节省空间,常用于10字节以上的数据。 ...
  • 详细介绍MySQL中的数据类型

    千次阅读 2022-04-12 21:46:07
    主要介绍了mysql中的数据类型,主要介绍整数类型,浮点类型,日期类型。开发中每个表都会存在主键和更新时间,这时候选择那个数据类型作为主键也是很重要的,如果选择的数据类型太大会浪费空间,如果选择小了会影响...
  • 相关文章:Redis简介以及和其他缓存数据库的区别前言Redis除了可以存储键还可以存储常见的5种数据类型,分别是:String、List、Set、Hash、ZSet。对于Redis的命令一部分是可以公用的,但是还有一些其他的命令是...
  • Redis数据类型应用场景

    万次阅读 多人点赞 2018-07-21 16:17:30
    本博客转自java思维导图公众号,大家可以关注,里面很多料,可以碎片化时间学习。这里主要为了记录归档,日后不断理解,因为看一遍吸收的难以应用自如。...Redis最为常用的数据类型主要以下...
  • redis常用的5种数据类型

    万次阅读 多人点赞 2018-03-27 16:56:39
    本文重要介绍,redis的五种数据类型,以及各应用场景,文章主要来源https://www.cnblogs.com/dijia478/p/8058775.html。 字符串string: 字符串类型是Redis中最为基础的数据存储类型,是一个由字节组成的序列...
  • 数据库的五种索引类型

    千次阅读 2020-09-21 10:13:57
    数据库的5索引类型 1. 普通索引 2. 唯一索引 3. 全文索引(FULLTEXT) 4. 单列索引、多列索引 5. 组合索引(最左前缀) 摘自
  • ORACLE数据库数据类型

    千次阅读 2019-11-28 17:51:42
    1、字符类型 • CHAR:一个定长字符串,当位数不足自动用空格填充来达到其最大长度。如非NULL的CHAR(12)总是包含12字节信息。CHAR字段最多可以存储2,000字节的 信息。 • VARCHAR2:目前这也是VARCHAR 的同义词。这...
  • 我对八种常见数据结构的理解

    万次阅读 2021-11-22 15:55:35
    所以存在即合理,每一种数据结构都它的特点,并不是哪种好,哪种坏 树 直接放图: 还有比这更容易理解的了吗? 如果不理解就把"A"节点当作爷爷,“D”节点当作父亲,"H"节点当作小孩 树是一种数据结构 它是由 n(n...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 311,181
精华内容 124,472
关键字:

常见数据类型有哪五种