Redis

1.redis特点

  1. 数据存储:存放在内存,还支持持久化.-存取速度快,并发能力强,数据安全性高
  2. 支持value类型
  3. 支持多个语言客户端
  4. 还支持集群(支持高并发,海量数据)

2.使用场景

  1. 缓存
  2. 计数器
  3. 实时防攻击系统
  4. 需要设置有效期的应用
  5. 自动去重应用
  6. 栈和队列
  7. 消息订阅系统

3.redis的安装

  1. 网址
  • 官网:https://redis.io/
  • 中文网:http://redis.cn/
  • redis的windows版的github下载地址:https://github.com/MicrosoftArchive/redis/releases
  1. 下载
  • 去github下载windows版,我这里下载的3.2.100版本
  1. 安装启动服务端
  • 由于redis是一款绿色的,不需要安装,直接启动服务端就好
  • 启动命令(在压缩包解压后的目录那里打开黑窗口):redis-server.exe redis.windows.conf
  1. 客户端安装启动
  • redis自带的客户端也是绿色的,无需安装,直接启动即可
  • 启动命令1(在压缩包解压后的目录那里打开黑窗口):redis-cli.exe -h 服务端ip -p 服务端redis的端口号
  • 启动命令2:直接双击redis-cli.exe文件

4.使用redis-cli.exe操作redis

见操作文档

5.java操作redis

  1. 选择java客户端jedis
  2. 创建普通java项目,导入2个jar
    • jedis-2.5.2.jar
    • commons-pool2-2.2.jar
  3. jedis连接方式操作redis
package cn.wangningbo.redis.client.jedis;

import org.junit.Test;
import redis.clients.jedis.Jedis;

public class JedisHello {
    @Test
    public void test() throws Exception {
        //连接redis
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        //设置key-value
        jedis.set("test", "easy");
        //获取key为test的value
        System.out.println(jedis.get("test"));
        //关闭连接
        jedis.close();
    }
}
  1. 连接池方式操作redis
package cn.wangningbo.redis.client.jedis;

import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolTest {
    @Test
    public void test() throws Exception {
        //创建配置对象
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //空闲时的连接数
        jedisPoolConfig.setMaxIdle(3);
        //最大连接数
        jedisPoolConfig.setMaxTotal(10);
        //创建连接超时 1秒
        jedisPoolConfig.setMaxWaitMillis(1 * 1000);
        //获取连接的时候测试连接是否畅通
        jedisPoolConfig.setTestOnBorrow(true);
        //创建jedis连接池   参数:指定配置,ip,端口
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379);
        //获取jedis
        Jedis jedis = jedisPool.getResource();
        //操作数据
        jedis.set("name", "二狗");
        System.out.println(jedis.get("name"));
        //释放连接
        jedis.close();
        //摧毁连接池
        jedisPool.destroy();
    }
}
  1. 封装工具类
package cn.wangningbo.redis.client.jedis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public enum JedisUtil {
    INSTANCE;
    private static JedisPool jedisPool;

    static {
        //创建配置对象
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //空闲时的连接数
        jedisPoolConfig.setMaxIdle(3);
        //最大连接数
        jedisPoolConfig.setMaxTotal(10);
        //创建连接超时 1秒
        jedisPoolConfig.setMaxWaitMillis(1 * 1000);
        //获取连接的时候测试连接是否畅通
        jedisPoolConfig.setTestOnBorrow(true);
        //创建jedis连接池   参数:指定配置,ip,端口
        jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379);
    }

    public Jedis getResource() {
        return jedisPool.getResource();
    }
}
  1. 工具类操作redis
package cn.wangningbo.redis.client.jedis;

import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.List;

public class JedisOprTest {
    Jedis jedis = JedisUtil.INSTANCE.getResource();

    @Test
    public void testKey() throws Exception {
        //清空数据
        jedis.flushAll();

        System.out.println("判断key为name的key是否存在:" + jedis.exists("name"));
        System.out.println("判断key为age的key是否存在:" + jedis.exists("age"));

        System.out.println("给key为name的key设置value:" + jedis.set("name", "二狗"));
        System.out.println("给key为age的key设置value:" + jedis.set("age", "18"));

        System.out.println("再次判断key为name的key是否存在:" + jedis.exists("name"));
        System.out.println("再次判断key为age的key是否存在:" + jedis.exists("age"));

        System.out.println("删除前key为name的value值:" + jedis.get("name"));
        System.out.println("删除key为name的value值:" + jedis.del("name"));
        System.out.println("删除后key为name的value值:" + jedis.get("name"));
        System.out.println("获取key为age的value值:" + jedis.get("age"));

        //获取所有的key
        jedis.keys("*").forEach(key -> {
            System.out.println(key + "-->" + jedis.get(key));
        });

        //释放连接
        jedis.close();
    }

    @Test
    public void testStringBase() throws Exception {
        //清空数据
        jedis.flushAll();
        //add
        jedis.set("name", "舔狗");
        //get
        System.out.println(jedis.get("name"));
        //update
        jedis.set("name", "二狗");
        //get
        System.out.println(jedis.get("name"));
        //del
        jedis.del("name");
        //get
        System.out.println(jedis.get("name"));
        //jedis.append(key,appStr)追加 字符串拼接
        jedis.set("age", "12");
        System.out.println(jedis.get("age"));
        jedis.append("age", "45");
        //jedis.get() 获取
        System.out.println(jedis.get("age"));

    }

    @Test
    public void testStringBatch() throws Exception {
        //清空数据
        jedis.flushAll();
        //jedis.mset(keyvalue,keyvalue) dd update
        jedis.mset("name", "二狗", "age", "19", "sex", "男");
        jedis.keys("*").forEach(key -> {
            System.out.println(key + "-->" + jedis.get(key));
        });
        //jedis.mget(key1,key2,key3....) //获取多个key的值返回list
        List mget = jedis.mget("name", "sex");
        System.out.println(mget);
        //jedis.del(key1,key2...) del
        jedis.del("name", "sex");
        jedis.keys("*").forEach(key -> {
            System.out.println(key + "-->" + jedis.get(key));
        });
    }

    @Test
    public void testStringAdvanceOpr() throws Exception {
        //清空数据
        jedis.flushAll();
        //设置一个key-value
        jedis.set("age", "19");
        System.out.println(jedis.get("age"));
        //jedis.incr()
        jedis.incr("age");
        System.out.println(jedis.get("age"));
        //jedis.incrBy()
        jedis.incrBy("age", 5);
        System.out.println(jedis.get("age"));
        //jedis.setex(key,time,value) //设置值得时候同时设置过期时间
        jedis.setex("name", 10, "奈斯");
        System.out.println(jedis.get("name"));
        Thread.sleep(12 * 1000);
        System.out.println(jedis.get("name"));
        System.out.println(jedis.exists("name"));
    }

    //事务四个特性
    // 1 原子性:一个事务中,多个操作是不可分割的,要么都成功,要么都失败.
    // 2 一致性:一个事务中,多个操作如果有一个失败了,其他要进行回滚保持数据一致性.
    // 3 隔离性:事务是隔离的,多个事务不会相互影响
    // 4 连续性(持续性):事务一旦开始,不能中止.
    @Test
    public void test() throws Exception {
        //手动回滚
    }
}

6.面试题

  1. 项目中那些地方用到Redis?
    • 缓存、计数器、实时防攻击系统、设置有效期的应用、自动去重应用、栈和队列、消息订阅系统!
  2. 使用什么来操作Redis?
    • 可以操作redis的客户端有很多种。比如:java、php、js、C/C++、C#、python等。
    • 我选择了java,java可操作redis的也有很多种。比如:Redisson、jedis等等很多种!
    • 我使用过jedis操作redis!
  3. 你使用过memcached?
    • 没有。但是我使用过redis。
    • redis与mencached的相同点:都是key-valueNosql,数据存储在内容中,读写效率高,都支持存储过期。
    • redis与mencached的不相同点:
      • 1)redis支持持久化.可以进行aof及rdb数据持久化到磁盘,从而进行数据备份或数据恢复等操作,较好的防止数据丢失的手段。。
      • 2)redis支持存储类型更多
      • 3)redis支持pub/sub消息订阅机制,可以用来进行消息订阅与通知。
      • 4)支持简单的事务需求,但业界使用场景很少,并不成熟
  4. 你为什么要使用reids?
    • 1)数据存储:存放在内存,还支持持久化.-存取速度快,并发能力强,数据安全性高
    • 2)支持value类型
    • 3)支持多个语言客户端
    • 4)还支持集群(支持高并发,海量数据)
  5. redis怎么实现栈和队列?
    • 队列和堆栈都可以用Redis的list数据类型实现,因为list支持以下操作
    • lpush/rpush,从左侧/右侧追加元素
    • lpop/rpop,从左侧/右侧弹出元素
    • llen,获取队列的长度
    • lindex,获取某个位置的元素
  6. 事务四大特性?
    • 1 原子性:一个事务中,多个操作是不可分割的,要么都成功,要么都失败.
    • 2 一致性:一个事务中,多个操作如果有一个失败了,其他要进行回滚保持数据一致性.
    • 3 隔离性:事务是隔离的,多个事务不会相互影响
    • 4 连续性(持续性):事务一旦开始,不能中止.
  7. 为什么要使用连接池?
    • 1)资源重用。由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
    • 2)更快的系统响应速度。数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
    • 3)新的资源分配手段。对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
    • 4)统一的连接管理,避免数据库连接泄漏。在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。一个最小化的数据库连接池实现:
  8. 说一下redis是怎么存储数据的?
    • redis为了考虑效率,保存数据在内容中.并且考虑数据安全性,还做数据持久化,如果满足保存策略,就会把内存的数据保存到数据rdb文件,还来不及保存那部分数据存放到aof更新日志中。在加载时,把两个数据做一个并集。
  9. redis数据满了时会怎么办?
    • 会执行淘汰策略
    • 淘汰一些数据,达到redis数据都是有效的。选择合适的淘汰策略进行淘汰。
    • 1)volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
    • 2)volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
    • 3)volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
    • 4)allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
    • 5)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    • 6)no-enviction(驱逐):禁止驱逐数据
    • redis 确定驱逐某个键值对后,会删除这个数据并,并将这个数据变更消息发布到本地(AOF 持久化)和从机(主从连接)。

你可能感兴趣的:(Redis)