redis安装,redis的数据类型和使用场景,Redis事务,Redis持久化,Redis淘汰策略

Redis简介

https://redis.io/docs/data-types/

Redis(Remote Dictionary Server )远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存也可持久化的日志型、Key-Value(NoSQL)数据库。

Redis的特点

  • 性能极高,基于内存,读的速度是110000次/s,写的速度是81000次/s
  • 丰富的数据类型,支持string、hash、list、set及zset多种数据类型
  • 原子性,所有操作都是原子性的,支持事务
  • 丰富的特性,支持发布订阅、通知、过期策略等
  • 支持持久化,可以将内存中的数据保存在磁盘中,重启后再次加载
  • 支持分布式,理论上可以无限扩展
  • 单线程,没有线程并发问题,Redis5.0后也支持多线程

应用场景:

1. 做为缓存,保存热点数据
2. 分布式锁、分布式ID、分布式Session
3. 消息队列
4. ...

安装Redis

Linux安装

安装c编译器

yum -y install gcc

下载redis

cd  /usr/local
wget http://download.redis.io/releases/redis-3.2.5.tar.gz

解压redis

tar -xvf redis-3.2.5.tar.gz
mv redis-3.2.5 redis

编译redis

cd redis
make

配置redis

修改redis.conf

# bind 127.0.0.1  去掉绑定本机IP,让其它机器访问
protected mode no 关闭保护模式

启动redis服务器

切换到src中

./redis-server ../redis.conf

启动redis客户端

./redis-cli

后台启用

在启用的redis目录下输入以下命令,进行下图修改

vim redis.conf

在这里插入图片描述

启动

src/redis-server ./redis.conf

密码设置

可设置-也可省略

设置了之后要记得重新启动

在这里插入图片描述

Windows安装

从官网下载redis的windows版本
https://github.com/tporadowski/redis/releases
解压后,双击redis-server.exe,就完成了Redis启动
在这里插入图片描述

Redis的数据类型

Redis数据类型有:

  • string 字符串
  • hash 哈希
  • list 列表
  • set 集合
  • zset 有序集合

string

字符串是基本的key-value结构,key和value最大512m,key不建议超过1k,值可以是各种格式的字符、JSON、二进制、编码后的图片。

应用场景:

  1. 缓存
  2. 分布式ID
  3. 分布式锁
  4. 全局Session
  5. 全局计数器

设置值

set 键 值
set name zhagnsan
set name zhagnsan EX 60  //EX是过期时间,单位是秒
setex name 60 zhangsan
set 键 值 NX 				  //NX键如果不存在就设置成功,存在就失败

读取值

get 键
get name

删除键

del 键名

递增/递减(值必须为数字)

incr 键  递增1
decr 键  递减1
incrby 键 递增量
decrby 键 递减量

hash

一个key下有多个key-value

应用场景:保存对象的多个属性

和string的对比,优势是:可以灵活读写对象的部分属性

设置对象属性

student是对象名称,name和age是属性名称

hmset student name zhangsan age 20
hset student name zhangsan age 20

在这里插入图片描述

读取对象属性

hmget student name
也阔以获取多个
hmget student name age

在这里插入图片描述

读取对象所有属性

hgetall student

删除对象属性

hdel student age

list

list采用链表结构保存多个数据,是有序的、可重复的。

应用场景:

  1. 模拟数组、栈、队列等数据结构
  2. 线型结构,如:粉丝、点赞列表
  3. 消息队列

在这里插入图片描述

左边入栈

lpush students zhangsan
lpush students lisi
lpush students wangwu

左边出栈

lpop students

右边入栈

rpush students zhangsan

右边出栈

rpop students

列表长度

llen key

读取列表,0和2是开始和结束位置(-1 代表全部)

lrange students 0 2

set

set是无序的、不可重复的集合。

应用场景:

  1. 点赞数(避免重复)
  2. 社交关系(共同关注、可能认识)

添加数据

sadd students zhangsan
sadd students lisi
sadd students wangwu zhaoliu

读取数据

smembers students

移除一个元素

srem key mamber1 mamber2

是否是其中元素

sismember students zhangsan

取交集

sinter key1 key2 ...

取差集

sdiff key1 key2 ...

取并集

sunion key1 key2 ...

zset

zset是有序的、不可重复的集合。

应用场景:

  1. 排行榜

添加数据,要添加一个score数字,按score排序

zadd key score value

读取数据

  1. zrangebyscore ,start和end是score最小和最大值
    zrevrangebyscore 反向读取zrangebyscore
zrangebyscore key start end 
  1. zrange ,start和end是开始和结束位置
    zrevrange 反向读取zrange
zrange key start end 

事务

Redis提供的事务是将多个命令打包,然后一次性、按照先进先出的顺序(FIFO)有序的执行。在执行过程中不会被打断(在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中),当事务队列中的所以命令都被执行(无论成功还是失败)完毕之后,事务才会结束。

事务相关命令

  • multi 启动事务
  • exec 提交事务
  • discard 放弃事务
  • watch 监视一个或多个键,如果有其他客户端修改键的值,事务将失败

事务操作

案例1:开启事务,正常执行,提交事务
在这里插入图片描述
案例2:开启事务,放弃事务,事务中的操作没有执行
在这里插入图片描述
案例3:开始事务,出现了语法错误,提交事务后,操作都没有执行
在这里插入图片描述
案例4:开始事务,出现数值错误(k1是字符串不能递增),提交事务后,其它的操作可以执行
在这里插入图片描述
案例5:监视score键,没有其它客户端修改,事务正常执行
在这里插入图片描述
案例6:监视score键,提交前打开另一个客户端修改score,提交事务后incrby score没有执行
在这里插入图片描述

Redis持久化

Redis数据保存在内存中,为避免关闭程序后数据的丢失,就需要将数据保存到磁盘文件上。

持久化策略

持久化策略包含

  • AOF:默认每秒对数据进行持久化
  • RDB:按条件触发持久化操作,满足任意一个条件
    1. 900 1 900秒中修改1次
    2. 300 10 300秒中修改10次
    3. 60 10000 60秒中修改10000次

配置方法

可以在redis.conf中配置持久化
如:RDB
在这里插入图片描述
启动AOF的配置

appendonly yes   开启AOF  
appendfsync everysec  每秒保存

选择持久化策略

我们如何选择RDB和AOF呢?视业务场景而定:

  • 允许少量数据丢失,性能要求高,选择RDB
  • 只允许很少数据丢失,选择AOF
  • 几乎不允许数据丢失,选择RDB + AOF

Redis淘汰策略

Redis中的数据太多可能导致内存溢出,Redis会根据情况淘汰一些数据。
Redis的内存上限:64位系统,上限就是内存上限;32位系统,最大是4G
配置最大内存:

max-memory  配置0就是无上限(默认)

淘汰策略

配置淘汰策略

maxmemory-policy

值:

  • noevication(默认)不淘汰

  • volatile-ttl 在过期键中淘汰存活时间短的键

  • allkeys-lru (推荐)使用LRU算法淘汰比较少使用的键
    LRU算法:Least Recently Used 最近最少使用算法,淘汰长期不用的缓存

    LFU算法:Least Frequently Used 频率最少使用算法,淘汰使用频率少的缓存

  • volatile-lru 在过期的键中淘汰较少使用的

  • allkeys-random 在所有键中随机淘汰

  • volatile-random 在过期键中随机淘汰

  • allkeys-lfu

  • volatile-lfu

Redis开发

编程式缓存

通过SpringBoot整合Redis的方式来实现缓存商品。
1)导入Redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2)添加配置文件

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.jedis.pool.max-active=100
spring.redis.jedis.pool.max-wait=100ms
spring.redis.jedis.pool.max-idle=100
spring.redis.jedis.pool.min-idle=10

3)配置类
配置RedisTemplate

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        // 配置序列化器
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson序列化器
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

4)使用RedisTemplate
常用方法:

  • ValueOperations opsForValue() 获得string类型的操作对象
  • HashOperations opsForHash 获得hash类型的操作对象

ValueOperations操作对象

  • set(key,value) 保存key-value
  • Object get(key) 读取value

使用缓存的步骤:

在这里插入图片描述

  1. 先查询缓存
  2. 如果查到直接返回
  3. 如果查不到,查询数据库
  4. 数据库查到,保存缓存中
  5. 数据库查不到返回null
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    public static final String KEY = "User-";

    //注入RedisTemplate对象
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

//    @Override
//    public User getUserById(Long id) {
//        //获得string类型的操作对象
//        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//        //查询redis中的用户
//        User user = (User) ops.get(KEY + id);
//        if(user == null){
//            log.info("如果redis没有该用户,就查数据库");
//            //如果redis没有该用户,就查数据库
//            user = this.getById(id);
//            if(user != null){
//                log.info("如果数据库查到,就保存到redis中");
//                //如果数据库查到,就保存到redis中
//                ops.set(KEY + id,user);
//                return user;
//            }
//        }else {
//            log.info("如果redis查到,就返回对象");
//            //如果redis查到,就返回对象
//            return user;
//        }
//        log.info("如果数据库没有查到,就返回null");
//        return null;
//    }

    // key-->User::1
    @Cacheable(cacheNames = "User",key = "T(String).valueOf(#id)")
    @Override
    public User getUserById(Long id) {
        return this.getById(id);
    }
}

声明式缓存

编程式缓存使用复杂,代码侵入性高,推荐使用声明式缓存,通过注解来实现热点数据缓存。

1)在启动类上添加注解

//启动缓存
@EnableCaching

2)Redis的配置类

@Configuration
public class RedisConfig {

    @Bean
    public RedisCacheConfiguration provideRedisCacheConfiguration(){
        //加载默认配置
        RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
        //返回Jackson序列化器
        return conf.serializeValuesWith(
                RedisSerializationContext.SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
    }
}

3)缓存相关注解

  • @CacheConfig 使用在Service类上,可以配置缓存名称,如:
    @CacheConfig(cacheNames = “books”)
  • @Cacheable 使用在查询方法上,让方法优先查询缓存
  • @CachePut 使用在更新和添加方法上,数据库更新和插入数据后同时保存到缓存里
  • @CacheEvict 使用在删除方法上,数据库删除后同时删除缓存

注意:缓存的实体类必须实现序列化接口

案例:Reids缓存品牌

//配置缓存名称为brand
@CacheConfig(cacheNames = "brand")
@Service
public class BrandServiceImpl extends ServiceImpl<BrandMapper, Brand> implements IBrandService {

    @Autowired
    private BrandMapper brandMapper;

	//按分类查询品牌时进行缓存,缓存名称是brand-category,键是分类id
    @Cacheable(cacheNames = "brand-category",key = "T(String).valueOf(#cid)")
    @Override
    public List<Brand> findBrandsByCategory(Integer cid) {
        return brandMapper.selectBrandsByCategory(cid);
    }

	//缓存单个品牌
    @Cacheable(key = "T(String).valueOf(#id)")
    @Override
    public Brand findBrandById(Long id) {
        return this.getById(id);
    }

	//修改品牌时更新缓存
    @CachePut(key = "T(String).valueOf(#brand.id)")
    @Override
    public Brand saveBrand(Brand brand) {
        this.saveOrUpdate(brand);
        return brand;
    }

	//删除品牌时删除缓存
    @CacheEvict(key = "T(String).valueOf(#id)")
    @Override
    public void deleteBrand(Long id) {
        this.removeById(id);
    }

	//缓存分页
    @Cacheable(cacheNames = "brand-page",key = "T(String).valueOf(#page)")
    @Override
    public IPage<Brand> pageBrands(Long page) {
        return this.page(new Page<>(page,10));
    }
}

组合注解@Cacing

同时完成多个查询、更新、删除的操作

@CacheConfig(cacheNames = "person")
@Service
public class PersonServiceImpl extends ServiceImpl<PersonMapper, Person> implements IPersonService {

    public static final String PREFIX = "Person:";

    @Autowired
    private PersonMapper personMapper;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Cacheable(cacheNames = "person",key = "T(String).valueOf(#id)")
    @Override
    public Person getPersonById(Long id) {
        return personMapper.selectById(id);
    }


    @Cacheable(cacheNames = "person-page",key = "T(String).valueOf(#current)")
    @Override
    public IPage<Person> getPersonPage(Long current, Long size) {
        return personMapper.selectPersonPage(new Page<Person>(current,size));
    }

    @Caching(put = @CachePut(cacheNames = "person",key = "T(String).valueOf(#person.id)"),
            evict = @CacheEvict(cacheNames = "person-page",allEntries = true))
    public Person addPerson(Person person){
        personMapper.insert(person);
        return person;
    }

    //同时更新person+id,和删除所有person-page缓存
    @Caching(put = @CachePut(cacheNames = "person",key = "T(String).valueOf(#person.id)"),
        evict = @CacheEvict(cacheNames = "person-page",allEntries = true))
    @Override
    public Person updatePerson(Person person) {
        personMapper.updateById(person);
        return person;
    }

    //同时删除person+id,和所有person-page缓存
    @Caching(evict = {@CacheEvict(cacheNames = "person",key = "T(String).valueOf(#id)"),
            @CacheEvict(cacheNames = "person-page",allEntries = true)})
    @Override
    public void deletePerson(Integer id) {
        personMapper.deleteById(id);
    }
}
  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值