zoukankan      html  css  js  c++  java
  • Docker入门实践笔记(三)一篇文章搞懂Docker下安装Redis,以及Redis与SpringBoot整合

    内容

      先介绍单机版Redis镜像在Docker下的安装,然后在容器的Redis Shell中进行常用类型String、List、Set、Hash、SortedSet的增删改查操作测试,最后再结合SpringBoot项目进行简单的测试。后续会推出哨兵模式(Sentinel,一主二从三哨兵)和集群模式(Redis Cluster)的安装和部署,敬请关注。

    版本

      操作系统: CentOS 7.2 64位

      Docker:17.12.1.ce

      Redis: 3.2.12

    适合人群

      linux运维人员,docker运维人员,java人员

    说明

      转载请说明出处:Docker入门实践笔记(三)一篇文章搞懂Docker下安装Redis,以及Redis与SpringBoot整合

      Demo源码托管:https://github.com/leo-zz/SpringBootDemo

    参考

      Docker官方文档:https://hub.docker.com/r/library/redis/

      Docker入门实践笔记(一)——安装Docker CE

      Linux入门实践笔记(三)——数据盘格式化和和多分区挂载

      spring boot整合redis

      Redis 命令参考:http://redisdoc.com/

    前提

      服务器需要安装Docker CE,未安装的童鞋请参考 Docker入门实践笔记(一)——安装Docker CE

      此示例将redis的缓存持久化到~/redis/data路径下,如果需要分区挂载数据盘的童鞋,请参考Linux入门实践笔记(三)——数据盘格式化和和多分区挂载

    步骤

    下载Redis镜像

      使用docker pull,从Docker仓库中下载Redis镜像,本示例下载的版本为3.2.12。使用docker images查看已经下载的镜像信息。

    #从Docker仓库中下载Redis镜像
    [user1@iz8vb62snc6e5cage5yvz9z /]$ sudo docker pull redis:3.2.12
    3.2.12: Pulling from library/redis
    f17d81b4b692: Pull complete
    b32474098757: Pull complete
    8980cabe8bc2: Pull complete
    58af19693e78: Pull complete
    a977782cf22d: Pull complete
    9c1e268980b7: Pull complete
    Digest: sha256:7b0a40301bc1567205e6461c5bf94c38e1e1ad0169709e49132cafc47f6b51f3
    Status: Downloaded newer image for redis:3.2.12
    #查看已经下载的镜像信息
    [user1@iz8vb62snc6e5cage5yvz9z home]$ sudo docker images
    REPOSITORY         TAG                 IMAGE ID           CREATED             SIZE
    redis               3.2.12             87856cc39862        8 days ago         76MB
    配置redis.conf

      将redis.conf拷贝到/home/user1/redis/config路径下,可以修改此文件以配置Redis;本示例使用默认配置。

    [user1@iz8vb62snc6e5cage5yvz9z config]$ ls
    redis.conf
    [user1@iz8vb62snc6e5cage5yvz9z config]$ pwd
    /home/user1/redis/config
    创建Redis容器

      使用docker run创建Redis容器,然后使用docker ps查看容器的运行情况。

    [user1@iz8vb62snc6e5cage5yvz9z redis]$ sudo docker run -p 6379:6379 
    -v /home/user1/redis/config:/usr/local/etc/redis/redis.conf -v /home/user1/redis/data:/data --name jmsRedis
    -d redis:3.2.12 redis-server /usr/local/etc/redis/redis.conf 14d9c846b6586953c9528a0d6cbfe3257f4a936892e8d8778260a7aaf62b79c7 [user1@iz8vb62snc6e5cage5yvz9z redis]$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 14d9c846b658 redis:3.2.12 "docker-entrypoint.s…" 15 seconds ago Up 15 seconds 0.0.0.0:6379->6379/tcp jmsRedis

      创建容器的参数释义:

      -p是指定容器到宿主机的端口映射,这里使用的是Redis的默认端口号6379,映射为宿主机的6379。

      -v是指定容器到宿主机的文件映射,这里将Redis容器的持久化数据存放路径/data映射到宿主机的/home/user1/redis/data;将Redis的配置文件/usr/local/etc/redis/redis.conf映射到宿主机的/home/user1/redis/config。

      --name是指定容器的名称为jmsRedis。

      -d表示在后台启动Redis。

      redis-server /usr/local/etc/redis/redis.conf 表示启动指定配置文件的Redis。

    容器内测试

      执行docker exec进入容器,由于容器中安装了Redis,故可以执行redis-cli命令进入Redis shell。

    [user1@iz8vb62snc6e5cage5yvz9z redis]$ sudo docker exec -it 14d9c846b658 /bin/bash  
    root@14d9c846b658:/data# redis-cli -h localhost -p 6379
    localhost:6379>
    测试String类型数据的增删改查

      演示Redis中String类型数据的的设置set、查询get、删除del操作。

    #将字符串值 value 关联到 key 。如果 key 已经持有其他值, SET 就覆写旧值,无视类型。
    #对于带有生存时间(TTL)的键来,当SET命令成功在这个键上执行时,这个键原有的TTL将被清除。
    #时间复杂度:O(1);返回值:设置操作成功完成时,返回 OK.
    localhost:6379> set hello leo
    OK
    ​
    #返回 key 所关联的字符串值。当 key 不存在时,返回 nil ,否则,返回 key 的值。
    #如果 key 不是字符串类型,那么返回一个错误。时间复杂度:O(1)
    localhost:6379> get hello
    "leo"#删除给定的一个或多个 key 。不存在的 key 会被忽略。返回值:被删除 key 的数量。
    #时间复杂度:O(N), N 为被删除的 key 的数量。删除单个字符串类型的 key ,时间复杂度为O(1)。删除单个列表、集合、有序集合或哈希表类型的 key ,
    时间复杂度为O(M), M 为以上数据结构内的元素数量。
    localhost:6379> del hello (integer) 1

    llocalhost:6379> get hello (nil)
    测试List类型数据的增删改查

      演示Redis中List类型数据的的插入rpush、范围查询lrange、按下标查询lindex、移除头元素lpop操作。

    #将一个或多个值 value 插入到列表 key 的表尾(最右边),索引依次递增。
    #时间复杂度:O(1),返回值:rpush后list的长度
    localhost:6379> rpush fruit apple
    (integer) 1
    localhost:6379> rpush fruit banana pear orange
    (integer) 4#返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。下标(index)参数 start 和 stop 都以 0 为底,
    也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素;也可以使用负数下标,以 -1 表示列表的最后一个元素,
    -2 表示列表的倒数第二个元素,以此类推。
    #时间复杂度:O(S+N), S 为偏移量 start , N 为指定区间内元素的数量。遍历1次链表拿取所有范围内的数据。 localhost:6379> lrange fruit 0 -1 1) "apple" 2) "banana" 3) "pear" 4) "orange"#返回列表 key 中,下标为 index 的元素。 时间复杂度O(N),需要遍历链表。 localhost:6379> lindex fruit 2 "pear"#移除并返回列表 key 的头元素。当 key 不存在时,返回 nil 。 #时间复杂度:O(1),头元素是指index最小的元素。所有元素的index会随着pop操作更新 localhost:6379> lpop fruit "apple" ​ localhost:6379> lrange fruit 0 -1 1) "banana" 2) "pear" 3) "orange"
    测试SET类型数据的增删改查

      演示Redis中Set类型数据的的插入sadd、集合查询smembers、判断成员是否存在sismember、移除成员srem操作。

    #将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略。
    #假如 key 不存在,则创建一个只包含 member 元素作成员的集合。当 key 不是集合类型时,返回一个错误。
    #时间复杂度:O(N), N 是被添加的元素的数量。返回值:被添加到集合中的新元素的数量,不包括被忽略的元素。
    localhost:6379> sadd animal tiger
    (integer) 1
    localhost:6379> sadd animal panda
    (integer) 1
    localhost:6379> sadd animal lion
    (integer) 1
    localhost:6379> sadd animal fish
    (integer) 1
    localhost:6379> sadd animal lion
    (integer) 0#返回集合 key 中的所有成员。不存在的 key 被视为空集合。
    #时间复杂度:O(N), N 为集合的基数。
    localhost:6379> smembers animal
    1) "panda"
    2) "tiger"
    3) "fish"
    4) "lion"#判断 member 元素是否集合 key 的成员。时间复杂度:O(1)
    #如果 member 元素是集合的成员,返回 1 。如果 member 元素不是集合的成员,或 key 不存在,返回 0 。
    localhost:6379> sismember animal panda
    (integer) 1#移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略。
    #时间复杂度:O(N), N 为给定 member 元素的数量。
    #返回值:被成功移除的元素的数量,不包括被忽略的元素。当 key 不是集合类型,返回一个错误。
    localhost:6379> srem animal panda
    (integer) 1
    ​
    localhost:6379> sismember animal panda
    (integer) 0
    测试HASH类型数据的增删改查

      演示Redis中Hash类型数据的的插入hset、集合查询hgetall、根据Key查询hget、移除hdel操作。

    #将哈希表 key 中的域 field 的值设为 value 。如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。
    #如果域 field 已经存在于哈希表中,旧值将被覆盖。
    #返回值:如果 field 是哈希表中的一个新建域,并且值设置成功,返回 1 。如果哈希表中域 field 已经存在且旧值已被新值覆盖,返回 0 。时间复杂度:O(1)
    localhost:6379> hset phones mi8 xiaomi
    (integer) 1
    localhost:6379> hset phones v10 honor
    (integer) 1
    localhost:6379> hset phones pro2 smartisan
    (integer) 1
    localhost:6379> hset phones nex vivo
    (integer) 1#返回哈希表 key 中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
    #时间复杂度:O(N), N 为哈希表的大小。
    localhost:6379> hgetall phones
    1) "mi8"
    2) "xiaomi"
    3) "v10"
    4) "honor"
    5) "pro2"
    6) "smartisan"
    7) "nex"
    8) "vivo"#删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。返回值:被成功移除的域的数量.
    #时间复杂度:O(N), N 为要删除的域的数量。
    localhost:6379> hdel phones pro2
    (integer) 1
    localhost:6379> hdel phones pro2
    (integer) 0#返回哈希表 key 中给定域 field 的值。时间复杂度:O(1);返回值:给定域的值,若不存在则返回nil。
    localhost:6379> hget phones pro2
    (nil)
    localhost:6379> hget phones mi8
    "xiaomi"
    ​
    localhost:6379> hgetall phones
    1) "mi8"
    2) "xiaomi"
    3) "v10"
    4) "honor"
    5) "nex"
    6) "vivo"
    测试Sorted set类型数据的增删改查

      演示Redis中Hash类型数据的的插入zadd、范围查询zrange、限定score的范围查询zrangebyscore、移除zrem操作。

    #Sorted Set新增/删除一个元素的复杂度为log(N),实现的数据结构感觉像是二叉树
    #将一个或多个 member 元素及其 score 值加入到有序集 key 当中。score 值可以是整数值或双精度浮点数。
    #如果某个 member 已经是有序集的成员,那么更新这个 member 的 score 值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。
    #时间复杂度:O(M*log(N)), N 是有序集的基数, M 为成功添加的新成员的数量。
    #返回值:被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
    localhost:6379> zadd zphones 1598 vivoZ3
    (integer) 1
    localhost:6379> zadd zphones 1599 oppoK1
    (integer) 1
    localhost:6379> zadd zphones 2499 XiaoMi8
    (integer) 1
    localhost:6379> zadd zphones 1299 SmartisanPro2
    (integer) 1#返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递增(从小到大)来排序。具有相同 score 值的成员按字典序(lexicographical order )来排列。
    #以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,支持负数下标,-1 表示最后一个成员,-2 表示倒数第二个成员
    #时间复杂度:O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
    localhost:6379> zrange zphone 0 -1
    (empty list or set)
    localhost:6379> zrange zphones 0 -1
    1) "SmartisanPro2"
    2) "vivoZ3"
    3) "oppoK1"
    4) "XiaoMi8"
    localhost:6379> zrange zphones 0 -1 withscores
    1) "SmartisanPro2"
    2) "1299"
    3) "vivoZ3"
    4) "1598"
    5) "oppoK1"
    6) "1599"
    7) "XiaoMi8"
    8) "2499"
    ​
    ​
    #返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。
    #可选的 LIMIT 参数指定返回结果的数量及区间,注意当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。
    #可选的 WITHSCORES 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 score 值一起返回。
    #min 和 max 可以是-inf和+inf,可以在不知道有序集的最低和最高score值的情况下使用
    localhost:6379> zrangebyscore zphones 999 1599 withscores
    1) "SmartisanPro2"
    2) "1299"
    3) "vivoZ3"
    4) "1598"
    5) "oppoK1"
    6) "1599"#移除有序集 key 中的一个或多个成员,不存在的成员将被忽略。当 key 存在但不是有序集类型时,返回一个错误。
    #时间复杂度:O(M*log(N)), N 为有序集的基数, M 为被成功移除的成员的数量。
    #返回值:被成功移除的成员的数量
    localhost:6379> zrem zphones SmartisanPro2
    (integer) 1
    ​
    localhost:6379> zrange zphones 0 -1 withscores
    1) "vivoZ3"
    2) "1598"
    3) "oppoK1"
    4) "1599"
    5) "XiaoMi8"
    6) "2499"
    搭建SpringBoot测试项目
    创建SpringBoot项目

      通过IDEA中的Spring Initializr创建SpringBoot项目。

    1540451706434

      Group和Artifact配置如下。

    1540452619089

      选择SpringBoot的版本为1.5.x,并勾选Redis的依赖。

    1540451800559

      选则项目所在路径。

    1540452660787

      项目创建完毕,可以删除maven wrapper相关的文件和文件夹。

    1540453560286

    POM

      在创建项目中已经勾选了Redis相关的依赖,不需要再在POM文件中添加其他依赖

    <!-- 可以看到Spring Initailizer已经帮我们引入了redis的依赖 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency><dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    yaml
    spring:
      redis:
       host: 192.168.1.25 #redis服务器的IP地址
       port: 6379 #redis监听的端口号
    Redis配置类
    @Configuration
    public class RedisConfig {
    ​
        /**
         * 注入 RedisConnectionFactory
         */
        @Autowired
        RedisConnectionFactory redisConnectionFactory;
    ​
        /**
         * 实例化 RedisTemplate 对象
         *
         */
        @Bean
        public RedisTemplate<String, Object> createRedisTemplate() {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            initializeRedisTemplate(redisTemplate, redisConnectionFactory);
            return redisTemplate;
       }
    ​
        /**
         * 设置数据存入 redis 的序列化方式
         *
         */
        private void initializeRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory redisConnectionFactory) {
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
            redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
            redisTemplate.setConnectionFactory(redisConnectionFactory);
       }
    ​
    ​
        /**
         * 实例化 HashOperations 对象,可以使用 Hash 类型操作
         *
         */
        @Bean
        public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
            return redisTemplate.opsForHash();
       }
    ​
        /**
         * 实例化 ValueOperations 对象,可以使用 String 操作
         *
         */
        @Bean
        public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
            return redisTemplate.opsForValue();
       }
    ​
        /**
         * 实例化 ListOperations 对象,可以使用 List 操作
         *
         */
        @Bean
        public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
            return redisTemplate.opsForList();
       }
    ​
        /**
         * 实例化 SetOperations 对象,可以使用 Set 操作
         *
         */
        @Bean
        public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
            return redisTemplate.opsForSet();
       }
    ​
        /**
         * 实例化 ZSetOperations 对象,可以使用 ZSet 操作
         *
         */
        @Bean
        public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
            return redisTemplate.opsForZSet();
       }
    ​
    }
    Redis工具类

      本示例主要进行Redis中Hash类型数据的操作。

    @Component
    public class RedisHashUtil<T> {
    ​
        @Autowired
        protected RedisTemplate<String, Object> redisTemplate;
        @Resource
        protected HashOperations<String, String, T> hashOperations;
    ​
        private String getRedisKey() {
            return "REDIS_DEMO";
       }
    ​
        /**
         * 添加
         *
         * @param key   key
         * @param value 对象
         * @param expire 过期时间(单位:秒),传入 -1 时表示不设置过期时间
         */
        public void put(String key, T value, long expire) {
            hashOperations.put(getRedisKey(), key, value);
            if (expire != -1) {
                redisTemplate.expire(getRedisKey(), expire, TimeUnit.SECONDS);
           }
       }
    ​
        /**
         * 删除
         *
         * @param key 传入key的名称
         */
        public void remove(String key) {
            hashOperations.delete(getRedisKey(), key);
       }
    ​
        /**
         * 查询
         *
         * @param key 查询的key
         * @return
         */
        public T get(String key) {
            return hashOperations.get(getRedisKey(), key);
       }
    ​
        /**
         * 获取当前redis库下所有value
         *
         * @return
         */
        public List<T> getAll() {
            return hashOperations.values(getRedisKey());
       }
    ​
        /**
         * 查询查询当前redis库下所有key
         *
         * @return
         */
        public Set<String> getKeys() {
            return hashOperations.keys(getRedisKey());
       }
    ​
        /**
         * 判断key是否存在redis中
         *
         * @param key 传入key的名称
         * @return
         */
        public boolean isKeyExists(String key) {
            return hashOperations.hasKey(getRedisKey(), key);
       }
    ​
        /**
         * 查询当前key下缓存数量
         *
         * @return
         */
        public long count() {
            return hashOperations.size(getRedisKey());
       }
    ​
        /**
         * 清空redis
         */
        public void clear() {
            Set<String> set = hashOperations.keys(getRedisKey());
            set.stream().forEach(key -> hashOperations.delete(getRedisKey(), key));
       }
    }
    测试类

      使用Redis中HASH类型数据结构存储key-value类型的缓存。

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RedisdemoApplicationTests {
    ​
        @Autowired
        RedisHashUtil<String> redisHashUtil;
    ​
        @Test
        public void firstRedisTest() {
            System.out.println("***********************测试向Redis插入数据");
            redisHashUtil.put("Mi8","XiaoMi",-1);
            redisHashUtil.put("V10","Honor",-1);
            redisHashUtil.put("Pro2","Smartisan",-1);
            redisHashUtil.put("NEX","VIVO",-1);
    ​
            System.out.println("**********************测试从Redis读取数据,以及查询数据总数");
            long count = redisHashUtil.count();
            List<String> all = redisHashUtil.getAll();
            System.out.println("遍历hash中的value,共计"+redisHashUtil.count()+"个品牌。分别为:");
            for (String s:all) {
                System.out.print(s+"   ");
            }
            System.out.println("");
    ​
            System.out.println("***********************测试Redis中是否存在指定数据");
            if(redisHashUtil.isKeyExists("Pro2")){
                String pro2 = redisHashUtil.get("Pro2");
                System.out.println("型号为Pro2的手机存在,其品牌为:"+pro2);
            }
    ​
            System.out.println("***********************测试从Redis中删除数据");
            redisHashUtil.remove("Pro2");
            if(!redisHashUtil.isKeyExists("Pro2")){
                System.out.println("型号为Pro2的手机被移除了");
            }
    ​
            System.out.print("剩余型号还有:");
            redisHashUtil.getKeys().forEach(key-> System.out.print(key+"  "));
            System.out.println("");
    ​
            System.out.println("***********************测试清空Redis中的hash数据");
            redisHashUtil.clear();
            System.out.println("所有手机型号都被清空,剩余:"+redisHashUtil.count()+"个");
        }
    ​
    }
    测试结果
    ***********************测试向Redis插入数据
    **********************测试从Redis读取数据,以及查询数据总数
    遍历hash中的value,共计4个品牌。分别为:
    XiaoMi   Honor   Smartisan   VIVO   
    ***********************测试Redis中是否存在指定数据
    型号为Pro2的手机存在,其品牌为:Smartisan
    ***********************测试从Redis中删除数据
    型号为Pro2的手机被移除了
    剩余型号还有:Mi8  V10  NEX  
    ***********************测试清空Redis中的hash数据
    所有手机型号都被清空,剩余:0个

      看到这的老铁都是真爱,源码已托管到GitHub,欢迎关注。

  • 相关阅读:
    图片自动播放
    选项卡切换
    jquery实现全选、反选、不选
    JQuery $()后面的括号里的内容什么时候加引号,什么时候不加
    ajax跨域jsonp
    加班与效率
    提问的智慧
    程序员要勇于说不
    编程从业五年的十四条经验,句句朴实
    成为高效程序员的7个重要习惯
  • 原文地址:https://www.cnblogs.com/lonelyJay/p/9858301.html
Copyright © 2011-2022 走看看