Redis

1.redis特点

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

2.使用场景

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

3.redis的安装

  1. 网址
  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<String> 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 持久化)和从机(主从连接)。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容