Redis 快速入门

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Redis 快速入门

点击上方蓝字关注“后端技术精选”

技术博文不错过!

作者:ITDragon龙
cnblogs.com/itdragon/p/7897131.html

cnblogs.com/itdragon/p/7897131.html

温馨提示:文中代码看不全可左右滑动

谈到Redis,大家应该都不陌生。它是用c语言开发的一个高性能键值数据库,主要用于缓存领域。

本章通过:

  • Redis的安装
  • Redis的五大数据类型
  • Redis的Java客户端
  • Redis与Spring 的整合
  • 来让读者对它有一个初步的了解。下一章再通过介绍配置文件来搭建Redis的主从模式和集群模式(配置大于编程,先从简单的编程入手)。

    效果图:

    Redis 快速入门

    需求:对商品类目进行Redis缓存处理

    技术:Redis,Spring,SpringMVC,Mybatis,EasyUI

    说明:EasyUI的树菜单上一章节有介绍,这里是为了方便展示效果。项目结构图中箭头所指的文件是需要重点学习的。若对EasyUI 树菜单感兴趣的可以访问:(该章节源码中提供商品类名的sql文件)

    http://blog.csdn.net/qq_19558705/article/details/78583888

    源码:见文章底部

    项目结构:

    Redis 快速入门

    Redis 安装

    安装文档:

    https://github.com/ITDragonBlog/daydayup/blob/master/Redis/Redis%E5%AE%89%E8%A3%85.md

    Redis 五大数据类型

    Redis 五大数据类型有String 类型,Hash 类型,List 类型,Set 类型,Zset(Sortedset)类型。其中常用的是前三个。

    官方提供的操作手册:

    http://redisdoc.com/

    在redis 自带的客户端中输入命令时,可以使用tab自动补齐,新手建议不要偷懒。

    String 类型

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

  • 赋值:set key value
  • 取值:get key
  • 批量赋值:mset key value … keyN valueN
  • 批量取值:mget key … keyN
  • 取值并赋值:getset key value
  • 删除key:del key … keyN
  • 数值加一:incr key
  • 数值加N:incrby key n
  • 数值减一:decr key
  • 数值减N:decrby key n
  • 字符串追加:append key value
  • 字符串长度:strlen key
  • 注 形如”key … keyN” 表示可以批量操作

    
    127.0.0.1:6379 set key value
    OK
    127.0.0.1:6379 get key
    "value"
    127.0.0.1:6379 mset key1 1 key2 2 key3 3
    OK
    127.0.0.1:6379 mget key1 key3
    1) "1"
    2) "3"
    127.0.0.1:6379 del key
    (integer) 1
    127.0.0.1:6379 incr count
    (integer) 1
    127.0.0.1:6379 incrby count 10
    (integer) 11
    127.0.0.1:6379 decr count
    (integer) 10
    127.0.0.1:6379 decrby count 5
    (integer) 5
    127.0.0.1:6379 set str itdragon
    OK
    127.0.0.1:6379 append str " blog!"
    (integer) 14
    127.0.0.1:6379 get str
    "itdragon blog!"
    127.0.0.1:6379 strlen str
    (integer) 14
    

    Hash 散列类型

    Redis hash 是一个键值对集合,和Java 的HashMap 类似。Redis hash 是一个String 类型的 field 和 value 的映射表,hash特别适合用于存储对象(key 可以是对象+id,field 是对象属性,value则是属性值)。

  • 给一个字段赋值:hset key field value
  • 给多个字段赋值:hmset key field value … fieldN valueN
  • 取一个字段的值:hget key field
  • 取多个字段的值:gmset key field … fieldN
  • 取所有的字段名和值:hgetall key
  • 删除字段名和值:hdel key field … fieldN
  • 判断字段是否存在:hexists key field
  • 获取key的所有field:hkeys key
  • 获取key的所有value:hvals key
  • 获取field个数:hlen key
  • 注:这里的field 就是 字段名,value 就是字段值

    
    127.0.0.1:6379 hset user name itdragon
    (integer) 1
    127.0.0.1:6379 hget user name
    "itdragon"
    127.0.0.1:6379 hmset user position java study redis
    OK
    127.0.0.1:6379 hmget user position study
    1) "java"
    2) "redis"
    127.0.0.1:6379 hgetall user
    1) "name"
    2) "itdragon"
    3) "position"
    4) "java"
    5) "study"
    6) "redis"
    127.0.0.1:6379 hdel user name 
    (integer) 1
    127.0.0.1:6379 hdel user position study
    (integer) 2
    127.0.0.1:6379 hexists user name
    (integer) 1
    127.0.0.1:6379 hexists user age
    (integer) 0
    127.0.0.1:6379 hkeys user
    1) "name"
    2) "position"
    3) "study"
    127.0.0.1:6379 hvals user
    1) "itdragon"
    2) "java"
    3) "redis"
    127.0.0.1:6379 hlen user
    (integer) 3
    

    List 类型

    Redis 列表是采用来链表来存储的简单字符串列表,按照插入顺序排序。添加元素一般从链表两端开始。

  • 向列表左侧加元素:lpush key value … valueN
  • 向列表右侧加元素:rpush key value … valueN
  • 遍历列表:lrange key startIndex endIndex
  • 获取List长度:llen key
  • 通过下标获取值:lindex key index
  • 通过下标设置值:lset key index value
  • 列表左侧移除第一个元素:lpop key
  • 列表右侧移除第一个元素:rpop key
  • 截取保留剩下的列表:ltrim key startIndex endIndex
  • 在制定元素插入值:linsert key after/before index value
  • 把集合第一个元素移到其他集合中:rpoplpush key otherListKey
  • 注:若endIndex=-1 表示最后一位;otherListKey 表示其他集合

    
    127.0.0.1:6379 lpush list 1 2
    (integer) 2
    127.0.0.1:6379 rpush list 3 4 
    (integer) 4
    127.0.0.1:6379 lrange list 0 -1
    1) "2"
    2) "1"
    3) "3"
    4) "4"
    127.0.0.1:6379 lpop list
    "2"
    127.0.0.1:6379 rpop list
    "4"
    127.0.0.1:6379 llen list
    (integer) 2
    127.0.0.1:6379 lindex list 1
    "3"
    127.0.0.1:6379 linsert list after 1 2
    (integer) 3
    127.0.0.1:6379 linsert list before 3 4
    (integer) 4
    127.0.0.1:6379 ltrim list 0 1
    OK
    127.0.0.1:6379 rpoplpush list newlist
    "1"
    

    Set 类型

    Redis 的 Set 是String类型的无序集合。它是通过HashTable实现实现的,用法和 List 类型很相似。

  • 新增集合元素:sadd key value … valueN
  • 删除集合元素:srem key value … valueN
  • 获取集合所有元素:smembers key
  • 判断集合元素是否存在:sismember key value
  • 集合差集:sdiff key1 key2
  • 集合交集:sinter key1 key2
  • 集合并集:sunion key1 key2
  • 获取集合长度:scard key1
  • 
    127.0.0.1:6379 sadd set a b c d
    (integer) 4
    127.0.0.1:6379 srem set a b c
    (integer) 3
    127.0.0.1:6379 smembers set
    1) "d"
    127.0.0.1:6379 sismember set a
    (integer) 0
    127.0.0.1:6379 sismember set d
    (integer) 1
    127.0.0.1:6379 sadd setA 1 2 3 
    (integer) 3
    127.0.0.1:6379 sadd setB 2 3 4
    (integer) 3
    127.0.0.1:6379 sdiff setA setB
    1) "1"
    127.0.0.1:6379 sdiff setB setA
    1) "4"
    127.0.0.1:6379 sinter setA setB
    1) "2"
    2) "3"
    127.0.0.1:6379 sunion setA setB
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    127.0.0.1:6379 scard setA
    (integer) 3
    

    Zset 类型

    Redis 的 zset(sorted set)和 set 一样也是string类型元素的集合,且不允许有重复的成员。不同的是 zset 的每个元素都会关联一个double类型的分数。zset正是通过分数来为集合中的成员进行排序。zset的成员是唯一的,但分数(score)却可以重复。

  • 新增集合元素:zadd key score value … scoreN valueN
  • 获取元素分数:zscore key value
  • 按照分数从小到大排序:zrange key startIndex endIndex
  • 按照分数从大到小排序:zrevrange key startIndex endIndex
  • 遍历时显示分数:withscores
  • 统计分数比value少的个数:zrank key value
  • 统计分数比value高的个数:zrevrank key value
  • 输出分数在制定值内的元素:zrangebyscore key score1 score2
  • 给元素加分:zincrby key score value
  • 获取元素个数:zcard()
  • 统计分数内的个数:zcount key score1 score2
  • 删除制定排名内的元素:zremrangebyrank key no1 no2
  • 删除指定分数内的元素:zremrangebyscore key score1 score2
  • 删除指定元素:zrem key value
  • 注: zcount 统计分数内的个数,score1 = keyScore = score2;zremrangebyrank 的 no1 和 no2 表示排名的第几位。

    
    127.0.0.1:6379 zadd zset 65 A 67 C 66 B
    (integer) 3
    127.0.0.1:6379 zscore zset C
    "67"
    127.0.0.1:6379 zrange zset 0 -1
    1) "A"
    2) "B"
    3) "C"
    127.0.0.1:6379 zrevrange zset 0 -1
    1) "C"
    2) "B"
    3) "A"
    127.0.0.1:6379 zrevrange zset 0 -1 withscores
    1) "C"
    2) "67"
    3) "B"
    4) "66"
    5) "A"
    6) "65"
    127.0.0.1:6379 zrank zset C
    (integer) 2
    127.0.0.1:6379 zrevrank zset C
    (integer) 0
    127.0.0.1:6379 zrangebyscore zset 65 66
    1) "A"
    2) "B"
    127.0.0.1:6379 zrangebyscore zset 65 66 limit 1 2
    1) "B"
    127.0.0.1:6379 zincrby zset 10 A
    "75"
    127.0.0.1:6379 zcard zset
    (integer) 3
    127.0.0.1:6379 zcount zset 65 66
    (integer) 1
    127.0.0.1:6379 zremrangebyrank zset 0 1
    (integer) 2
    127.0.0.1:6379 zremrangebyscore zset 100 200
    (integer) 0
    127.0.0.1:6379 zrem zset A
    (integer) 1
    

    Jedis客户端

    Jedis 是比较主流的 Redis Java 客户端。

    第一步:导入Jedis需要的jar

    
    !-- Redis客户端 --
    dependency
        groupIdredis.clients/groupId
        artifactIdjedis/artifactId
        jedis.version2.7.2/jedis.version
    /dependency
    

    第二步:单元测试类

    Jedis 的语法和 Redis 几乎一样,如果学好了Redis,Jedis也就没问题了,可谓是买一送一。建议使用连接池的方式。

    
    package com.itdragon.redis;
    import java.util.HashMap;
    import java.util.Map;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.junit.Test;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    public class TestJedisOperate {
    
        private final static String HOST = "112.74.83.71";
        private final static int PORT = 6379;
    
        /**
         * jedis 的语法和 redis 的语法几乎一致,比较常用的有Hash,String,List
         */
        @Test
        public void jedisSignle() {
            Jedis jedis = new Jedis(HOST, PORT);
            jedis.set("account", "itdragon");
            System.out.println("set , get 操作 : " + jedis.get("account"));
            jedis.mset("account:01", "itdragon01", "account:02", "itdragon02");
            System.out.println("mset , mget 操作 : " + jedis.mget("account:01", "account:02"));
            jedis.hset("user", "name", "ITDragon");
            System.out.println("hset , hget 操作 : " + jedis.hget("user", "name"));
            MapString, String userMap = new HashMap();
            userMap.put("password", "123456");
            userMap.put("position", "Java");
            jedis.hmset("user", userMap);
            System.out.println("hmset , hmget 操作 : " + jedis.hmget("user", "name", "password", "position"));
            if (0 == jedis.llen("userList")) {
                jedis.lpush("userList", "1", "2", "3");
            }
            System.out.println("List 类型 lpush , lrange 操作 : " + jedis.lrange("userList", 0, -1));
            jedis.sadd("userSet", "1", "2", "2");
            System.out.println("Set 类型 sadd , smembers 操作 : " + jedis.smembers("userSet"));
            MapString, Double scoreMembers = new HashMap();
            scoreMembers.put("A", 65.0);
            scoreMembers.put("C", 67.0);
            scoreMembers.put("B", 66.0);
            jedis.zadd("userScore", scoreMembers);
            System.out.println("Set 类型 zadd , zrange 操作 : " + jedis.zrange("userScore", 0, -1));
            jedis.close();
        }
    
        @Test
        public void testJedisPool() {
            JedisPool pool = new JedisPool(HOST, PORT);
            Jedis jedis = pool.getResource();
            System.out.println("通过连接池获取 key 为 account 的值 : " + jedis.get("account"));
            jedis.close();
            pool.close();
        }
    
    }
    

    Spring 整合 Redis

    创建用于整合redis的文件 applicationContext-jedis.xml

    建议使用redis 默认配置(默认,让生活更美好)

    
    ?xml version="1.0" encoding="UTF-8"?
    beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"
        !-- 加载配置文件 --
        context:property-placeholder location="classpath:resource/*.properties" /
        !-- 连接池配置 (可以用 redis 默认配置,效果可能会更好)--
        bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"
            !-- 最大连接数 --
            property name="maxTotal" value="30" /
            !-- 最大空闲连接数 --
            property name="maxIdle" value="10" /
            !-- 每次释放连接的最大数目 --
            property name="numTestsPerEvictionRun" value="1024" /
            !-- 释放连接的扫描间隔(毫秒) --
            property name="timeBetweenEvictionRunsMillis" value="30000" /
            !-- 连接最小空闲时间 --
            property name="minEvictableIdleTimeMillis" value="1800000" /
            !-- 连接空闲多久后释放, 当空闲时间该值 且 空闲连接最大空闲连接数 时直接释放 --
            property name="softMinEvictableIdleTimeMillis" value="10000" /
            !-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 --
            property name="maxWaitMillis" value="1500" /
            !-- 在获取连接的时候检查有效性, 默认false --
            property name="testOnBorrow" value="true" /
            !-- 在空闲时检查有效性, 默认false --
            property name="testWhileIdle" value="true" /
            !-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true --
            property name="blockWhenExhausted" value="false" /
        /bean 
        !-- jedis客户端单机版 --
        bean id="redisClient" class="redis.clients.jedis.JedisPool"
            constructor-arg name="host" value="${redis.host}" /
            constructor-arg name="port" value="${redis.ip}" /
            !-- constructor-arg name="poolConfig" ref="jedisPoolConfig" / --
        /bean
        bean id="jedisClient" class="com.itdragon.common.utils.JedisClientSingle"/
    /beans
    

    简单封装了Jedis 常用方法 JedisClientSingle.java

    
    package com.itdragon.common.utils;
    import org.springframework.beans.factory.annotation.Autowired;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    // 单例的Redis 工具类
    public class JedisClientSingle {
    
        /**
         * connect timed out 问题: 
         * 1. 检查redis服务是否开启
         * 2. 检查是否是因为防火墙的问题
         * 3. 检查网络问题(如果在同一个局域网内几乎不会出现这个问题)
         * Jedis jedis =new Jedis(HOST,PORT,100000);
         * JedisPool pool = new JedisPool(poolConfig, HOST, PORT, 100000);
         */
    
        @Autowired
        private JedisPool jedisPool; 
    
        public String get(String key) {
            Jedis jedis = jedisPool.getResource();
            String string = jedis.get(key);
            jedis.close();
            return string;
        }
    
        public String set(String key, String value) {
            Jedis jedis = jedisPool.getResource();
            String string = jedis.set(key, value);
            jedis.close();
            return string;
        }
    
        public String hget(String hkey, String key) {
            Jedis jedis = jedisPool.getResource();
            String string = jedis.hget(hkey, key);
            jedis.close();
            return string;
        }
    
        public long hset(String hkey, String key, String value) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.hset(hkey, key, value);
            jedis.close();
            return result;
        }
    
        public long del(String key) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.del(key);
            jedis.close();
            return result;
        }
    
        public long hdel(String hkey, String key) {
            Jedis jedis = jedisPool.getResource();
            Long result = jedis.hdel(hkey, key);
            jedis.close();
            return result;
        }
    
    }
    

    获取商品类名接口实现类 ProductCategoryServiceImpl.java

    
    package com.itdragon.service.impl;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.util.CollectionUtils;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import com.itdragon.common.pojo.EUTreeNode;
    import com.itdragon.common.pojo.ResponseResult;
    import com.itdragon.common.utils.JedisClientSingle;
    import com.itdragon.common.utils.JsonUtils;
    import com.itdragon.mapper.ProductCategoryMapper;
    import com.itdragon.pojo.ProductCategory;
    import com.itdragon.pojo.ProductCategoryExample;
    import com.itdragon.pojo.ProductCategoryExample.Criteria;
    import com.itdragon.service.ProductCategoryService;
    
    @Service
    public class ProductCategoryServiceImpl implements ProductCategoryService {
    
        @Autowired
        private ProductCategoryMapper categoryMapper;
    
        @Autowired
        private JedisClientSingle jedisClientSingle;
    
        @Value("${CATEGROY_ID_CACHE_REDIS_KEY}")
        private String CATEGROY_ID_CACHE_REDIS_KEY;
    
        @Override
        public ListEUTreeNode getCategoryList(Long parentId) {
            long startTime = System.currentTimeMillis();
            ListEUTreeNode resultList = new ArrayList();
            // 从redis缓存中取内容
            try {
                String cacheDatas = jedisClientSingle.hget(CATEGROY_ID_CACHE_REDIS_KEY, parentId.toString());
                if (StringUtils.isNotBlank(cacheDatas)) {
                    ListProductCategory categories = JsonUtils.jsonToList(cacheDatas, ProductCategory.class);
                    for (ProductCategory category : categories) {
                        EUTreeNode node = new EUTreeNode();
                        node.setId(category.getId());
                        node.setText(category.getName());
                        node.setState(category.getIsParent()?"closed":"open");
                        resultList.add(node);
                    }
                    System.out.println("redis cache Time : " + (System.currentTimeMillis() - startTime));
                    return resultList;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            ProductCategoryExample example = new ProductCategoryExample();
            Criteria criteria = example.createCriteria();
            criteria.andStatusEqualTo(1);
            criteria.andParentIdEqualTo(parentId); // 查询父节点下的所有子节点
            ListProductCategory productCategories = categoryMapper.selectByExample(example);
    
            for (ProductCategory category : productCategories) {
                EUTreeNode node = new EUTreeNode();
                node.setId(category.getId());
                node.setText(category.getName());
                node.setState(category.getIsParent()?"closed":"open");
                resultList.add(node);
            }
            System.out.println("No redis cache Time : " + (System.currentTimeMillis() - startTime));
            // 向redis缓存中添加内容
            try {
                jedisClientSingle.hset(CATEGROY_ID_CACHE_REDIS_KEY, parentId.toString(), JsonUtils.objectToJson(productCategories));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return resultList;
        }
    
        // 后面的内容看源码...
    }
    

    源码:

    https://github.com/ITDragonBlog/daydayup/tree/master/Redis

    到这里,Redis 的快速入门就结束了。下一章节介绍Redis 的主从和集群。

    如果你觉得文章不错,欢迎点赞分享到朋友圈

    Redis 快速入门

    原文始发于微信公众号(后端技术精选):

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Redis 快速入门


      转载请注明: 好好学java Redis 快速入门

     上一篇
    Redis持久化方式的选择 Redis持久化方式的选择
    本文将介绍Redis持久化的两种方式:快照持久化和AOF持久化,并对两种方法进行分析和对比,方便在实际中做出选择。 持久化什么是持久化Redis所有数据保存在内存中,对数据的更新将异步地保存到磁盘上,使得数据在Redis重启之后仍然存在。这
    2021-04-05
    下一篇 
    基于redis的分布式锁的分析与实践 基于redis的分布式锁的分析与实践
    作者:菜蚜my.oschina.net/wnjustdoit/blog/1606215 my.oschina.net/wnjustdoit/blog/1606215 前言:在分
    2021-04-05