Redis基础知识与Spring整合

67 阅读5分钟

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());
    }
}



www.nowcoder.com/study/live/… www.nowcoder.com/study/live/…