Redis缓存

66 阅读5分钟

缓存机制

为了提告数据库的查询能力,引入了缓存服务器,用户连续查询相同的数据时可以直接从缓存中取出.

缓存机制介绍

使用缓存机制就是为了降低用户访问物理设备的频次,从缓存服务器中获取数据,而不是服务器中,提高整体速度,提升用户体验.

如何实现缓存机制

1. 缓存使用的数据结构 Key=Value 且 Key必须唯一
2. 应该使用什么语言开发 C语言
3. 缓存的运行环境 内存中
4. 内存数据断电即擦除如何保证数据安全 实现持久化(写入磁盘中)
5. 内存数据如何优化 LRU算法/LFU算法

Redis介绍

*Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库,缓存,消息中间件,他支持多种类型的数据结构,例:字符串(String),散列(hashes),列表(lists),集合(sets),有序集合(sorted sets) *与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability).
速度快:
tomcat: 150-220/秒
nginx: 3-5万/秒
redis: 写 8.6万/秒 读 11.2万/秒 ~ 平均10万次/秒

安装Redis

1.在虚拟机指定位置上传Redis
位置上传Redis

2.解压Redis
tar -xvf redis.tar.gz
解压Redis
3.编译Redis
进入redis安装目录 make
编译Redis
4.安装Redis
需进入安装目录:make install
安装Redis
5.修改Redis配置文件(redis.conf)
vim redis.conf
1: 修改IP绑定.将Redis自带的IP绑定注释
行数69
2. 取消保护模式
取消保护模式
3. 开启开机后台启动
yes

Redis常规命令

复制redis-conf到安装目录下 即有server的目录下
1. 启动命令 redis-server redis-conf(没开启后台运行效果)

没开启后台运行效果
开启后台运行效果
2. 检索redis服务 ps -ef | grep redis
redis服务已启动
3.进入redis客户端 redis-cli -p 6379
进入成功
4.关闭redis
方式1:rediscli -p 6379 shutdown
方拾2: ps -ef | grep redis查看进程kill杀死进程

在这里插入图片描述

Redis入门

1.添加jar包

<!--spring整合redis -->
<dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
</dependency>

测试API

动态获取Redis对象(Jedis)
1.创建redis.properyies配置文件

#配置单台的Redis
redis.host=192.168.126.129
redis.port=6379

2.创建配置类RedisConfig并动态赋值
此处的
@Bean是将对象交给sping容器管理@Configuration表示这是个配置类
@PropertySource指明配置文件来源

@Configuration //表示配置类
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;
    @Bean
    public Jedis  jedis(){
        return new Jedis(host,port);
    }
}

3.创建测试类并注入自行配置的Redis对象
错误检查:
1.Linux防火墙
2.Redis三项配置
3.重启Redis

@SpringBootTest //需要依赖Spring容器,从容器中获取对象
public class TestRedis {
	@Autowired
    private Jedis jedis;
}

String类型测试

测试一
向Redis中存数据

@Test
public void test01() {
        //1.向Redis中存数据
        jedis.set("1", "憨批曲佳磊憨批齐亚硕");
        //2.从Redis中取值
        String value = jedis.get("1");
        System.out.println(value);
    }

测试二
API:
exists 检查Redis中是否存在某个值
expire 设定Key超时自动销毁时间
ttl 获取剩余生存时间
persist 撤销删除操作

@Test
    public void test02() {
        //1.判断Redis中是否存在某个key
        if (jedis.exists("1")) {
            //2.如果存在则设定超时时间
            jedis.expire("1", 100);
            //3.线程暂停2秒
            try {
                Thread.sleep(2000);
                //4.获取key的剩余生存时间
                Long time = jedis.ttl("1");
                System.out.println("生命倒计时" + time);
                //5.撤销删除操作
                jedis.persist("1");
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
        }
    }

测试三
redis的set操作会将之前的value覆盖
API : setnx 如果值存在则不执行赋值
操作之前检查Redis中是否有改数据

@Test
    public void test03() {
        jedis.flushAll();//清空redis缓存
        jedis.setnx("boos", "马化腾");
        jedis.setnx("boos", "马云");
        System.out.println(jedis.get("boos"));
    }

测试四
保证原子性如何操作(妖魔同时成功,妖魔同时失败)
API:setex 保证原子性操作并添加超时时间

@Test
    public void test04() {
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        jedis.setex("aaa", 20, "xxxx");//满足原子性需求
    }

测试五
同时添加超时时间并且满足原子性要求
API:SetParams设置参数 set传入参数即可
private static final String XX = “xx”; 只有key存在时才能赋值
private static final String NX = “nx”; 只有key不存在时才能赋值
private static final String PX = “px”; 毫秒
private static final String EX = “ex”; 秒

 @Test
    public void test05() {
        SetParams setParams = new SetParams();
        setParams.nx().ex(20);
        jedis.set("AAA", "w", setParams);
        String s = jedis.get("AAA");
        System.out.println(s);
    }

Hash类型测试

可以用散列类型保存对象和属性值

@Test
    public void testHash() {
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        jedis.hset("person", "name", "tomcat");
        jedis.hset("person", "age", "100");
        Map<String, String> person = jedis.hgetAll("person");
        System.out.println(person);
    }

Lsit类型测试

List集合当做队列使用也可以当做栈使用
队列:存入数据的方向和获取数据的方向相反
栈:存入数据的方向和获取数据的方向相同
API:
lpush 从队列的左边入队一个或多个元素
rpush 从队列的右边入队一个或多个元素
lpop 从队列的左端出队一个元素
rpop 从队列的右端出队一个元素
lpushx 当队列存在时从队列的左侧入队一个元素
rpushx 当队列存在时从队列的右侧入队一个元素

 @Test
    public void testList() {
        Jedis jedis = new Jedis("192.168.126.129", 6379);
        jedis.lpush("list", "1", "2", "3", "4", "5");
        String value = jedis.rpop("list");
        System.out.println(value);
        System.out.println(jedis.rpop("list"));
    }

Redis事务控制

API:
multi 标记一个事务开始
exec 执行所有multi之后发的命令
discard 丢弃所有multi之后发的命令
Transaction transaction = jedis.multi(); 事务对象
transaction.exec(); 提交事务
transaction.discard();回滚事务

@Test
    public void testMulti() {
        Transaction transaction = jedis.multi();
        try {
            transaction.set("AAA", "XXX");
            transaction.set("BBB", "XXX");
            transaction.exec(); //提交事务
        }catch (Exception exception){
            exception.printStackTrace();
            transaction.discard();//回滚事务
        }

    }