Redis是一种基于键值对的NoSQL数据库,它的值支持多种数据结构:字符串、哈希、列表(list)、集合(set)、有序集合(sorted set)



Redis优点:

Redis是将数据都存到内存里,所以它的读写性能非常好。为了避免服务器关闭后,数据丢失的问题,Redis将内存中的数据以快照或日志的形式保存到硬盘上,以保证安全性。从而达到速度与安全机能的兼顾。

  • 快照是指将内存中的数据原原本本的复制到硬盘上,毕竟数据总量也小,但是复制的过程是耗时的,如果当时还在处理其他业务,就可能会发生阻塞。所以不适合实时更新,而是每隔一段时间执行一次备份。
  • 日志方式是指每执行一个Redis命令,就存下该命令到内存,实时性好。但它是以追加的形式存的,虽说单条命令体积很小,但积累下来就很大了,恢复的时候,是把之前所有的命令从头到尾再跑一遍,时间很慢


应用场景:缓存、排行榜、计数器、消息队列。总的来说,需要频繁访问的数据,就适合用Redis。



Redis全局命令

redis-cli		// 打开redis数据库
select index // 按下标选择Redis 16个库中的一个 (下标从0开头)
flushdb // 清空当前库
keys * // 查看所有key
keys pre* // 查看以pre开头的key
exists user // 查看某个key是否存在
del user // 删除某个key
type user // 查看某个key的类型
expire user 10 // 设置某个key的过期时间(user存10毫秒)

规定key变量如果由两个单词拼接而成,那么需要用冒号来拼



Redis存取不同数据类型数据的命令

存取string类型(key: user_Name,value: ‘张三’)

set user_Name zhangsan	// 输入
get user_Name // 输出: "张三"


存取hash类型(user对象 key: id,value: 1;key: name,value: zhangsan)

hset user id 1		// 输入
hset user name zhangsan
hget user id // 输出: "1"
hget user name // 输出: "zhangsan"


存取list类型(ids对象 ,元素分别为:101, 102, 103)

比较特殊,可以看成一种横向的容器。支持从左边往里输入,也支持从右边往里输入;同样,也支持从左边或者右边取。因此,可以实现队列(左进右出)或栈(左进左出)的功能

lpush ids 101 102 103     	// lpush表示从left方向push。(左进)     
// 首先进101,然后在101的左边进102,然后在102的左边进103 因此,最后的存储空间就是:103 102 101

llen ids // 输出: (integer)3 (计算长度)
lindex ids 0 // 输出: "103" (左进左出,相当于栈)
lrange ids 0 2 // 输出: "103" "102" "101" (批量输出)
rpop ids // 输出: "101" (左进右出,相当于队列)
rpop ids // 输出: "102"

rpush ids 101 102 103 // rpush表示从right方向push。(右进)
首先进101,然后在101的右边进102,然后在102的右边进103 因此,最后的存储空间就是:101 102 103


存取set类型(user对象,元素分别为:aaa bbb ccc ddd eeee)

sadd user aaa bbb ccc ddd eee	// 输入
scard user · // 输出: (integer)5 (计算长度)
spop user // 输出: "ddd" (从集合中从随机弹出一个元素)
smembers user // 输出: "bbb" "ccc" "eee" "aaa" (无序打印集合中的元素)


存取sorted set类型(user对象,元素分别为:aaa bbb ccc ddd eeee)

利用分数对元素进行排序,分数在值前面输入

zadd user 20 aaa 10 bbb 40 ccc 30 ddd 50 eee	// 输入
zcard user // 输出: (integer)5 (计算长度)
zscore user ccc // 输出: "40" (输出某个值的分数)
zrank user aaa // 输出: (integer)1 (返回某个值的排名,下标从0开始,默认值越小排名越靠前)
zrange user 0 2 // 输出: "bbb" "aaa" "ddd" (返回排名在某个区间内的值)




Spring整合Redis

1、引入依赖

  • spring-boot-starter-data-redis


2、配置Redis(毕竟它也是数据库)

  • 配置数据库参数

    spring.redis.database=11   		选择16个数据库中的一个
    spring.redis.host=localhost
    spring.redis.port=6379 redis的默认端口号
  • 编写配置类,构造RedisTemplate

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.RedisSerializer;

    @Configuration
    public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
    //参考spring的RedisAutoConfiguration进行修改
    RedisTemplate<String, Object> template = new RedisTemplate();
    template.setConnectionFactory(factory);

    // 设置key的序列化方式
    template.setKeySerializer(RedisSerializer.string());
    // 设置value的序列化方式
    template.setValueSerializer(RedisSerializer.json());
    // 设置hash的key的序列化方式
    template.setHashKeySerializer(RedisSerializer.string());
    // 设置hash的value的序列化方式
    template.setHashValueSerializer(RedisSerializer.json());

    template.afterPropertiesSet();
    return template;
    }
    }


3、访问测试

import static org.junit.jupiter.api.Assertions.*;

import cn.hsy.community.CommunityApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import javax.swing.*;
import java.util.concurrent.TimeUnit;



@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisConfigTest {
@Autowired
private RedisTemplate redisTemplate;

@Test
public void testStrings() {
String redisKey = "test:count";

redisTemplate.opsForValue().set(redisKey, 1);

System.out.println(redisTemplate.opsForValue().get(redisKey));
System.out.println(redisTemplate.opsForValue().increment(redisKey));
System.out.println(redisTemplate.opsForValue().decrement(redisKey));
}

@Test
public void testHashes() {
String redisKey = "test:user";

redisTemplate.opsForHash().put(redisKey, "id", 1);
redisTemplate.opsForHash().put(redisKey, "username", "zhangsan");

System.out.println(redisTemplate.opsForHash().get(redisKey, "id"));
System.out.println(redisTemplate.opsForHash().get(redisKey, "username"));
}

@Test
public void testLists() {
String redisKey = "test:ids";

redisTemplate.opsForList().leftPush(redisKey, 101);
redisTemplate.opsForList().leftPush(redisKey, 102);
redisTemplate.opsForList().leftPush(redisKey, 103);

System.out.println(redisTemplate.opsForList().size(redisKey));
System.out.println(redisTemplate.opsForList().index(redisKey, 0));
System.out.println(redisTemplate.opsForList().range(redisKey, 0, 2));

System.out.println(redisTemplate.opsForList().leftPop(redisKey));
System.out.println(redisTemplate.opsForList().leftPop(redisKey));
System.out.println(redisTemplate.opsForList().leftPop(redisKey));
}

@Test
public void testSets() {
String redisKey = "test:teachers";

redisTemplate.opsForSet().add(redisKey, "刘备", "关羽", "张飞", "赵云", "诸葛亮");

System.out.println(redisTemplate.opsForSet().size(redisKey));
System.out.println(redisTemplate.opsForSet().pop(redisKey));
System.out.println(redisTemplate.opsForSet().members(redisKey));
}

@Test
public void testSortedSets() {
String redisKey = "test:students";

redisTemplate.opsForZSet().add(redisKey, "唐僧", 80);
redisTemplate.opsForZSet().add(redisKey, "悟空", 90);
redisTemplate.opsForZSet().add(redisKey, "八戒", 50);
redisTemplate.opsForZSet().add(redisKey, "沙僧", 70);
redisTemplate.opsForZSet().add(redisKey, "白龙马", 60);

System.out.println(redisTemplate.opsForZSet().zCard(redisKey));
System.out.println(redisTemplate.opsForZSet().score(redisKey, "八戒"));
System.out.println(redisTemplate.opsForZSet().reverseRank(redisKey, "八戒"));
System.out.println(redisTemplate.opsForZSet().reverseRange(redisKey, 0, 2));
}

@Test
public void testKeys() {
redisTemplate.delete("test:user");

System.out.println(redisTemplate.hasKey("test:user"));

redisTemplate.expire("test:students", 10, TimeUnit.SECONDS); // 设置时间的单位
}

// 多次访问同一个key, 可以把这个key绑定在某个对象上
@Test
public void testBoundOperations() {
String redisKey = "test:count";
BoundValueOperations operations = redisTemplate.boundValueOps(redisKey); // operations就是绑定了"test:count"的对象
operations.increment(); // 反复访问(+1)
operations.increment();
operations.increment();
operations.increment();
operations.increment();
System.out.println(operations.get());
}
}




https://www.nowcoder.com/study/live/246/4/1
https://www.nowcoder.com/study/live/246/4/7