数据库
首页 > 数据库> > 仿牛客网社区开发——第4章 Redis,一站式高性能存储方案

仿牛客网社区开发——第4章 Redis,一站式高性能存储方案

作者:互联网

Redis 入门

• Redis 是一款基于键值对NoSQL 数据库,它的值支持多种数据结构:

字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。

• Redis 将所有的数据都存放在内存中,所以它的读写性能十分惊人。同时,Redis 还可以将内存中的数据以快照日志的形式保存到硬盘上,以保证数据的安全性。

快照:把内存中的所有数据存放到硬盘上,占用空间小,恢复速度快;但是存放过程比较耗时间,一般作为备份使用

日志:存取每一条执行的 Redis 命令,实时,速度快;但是日志占用空间大,且恢复起来需要逐条执行命令,时间较长

• Redis典型的应用场景包括:缓存、排行榜、计数器、社交网络、消息队列(不如专业的消息队列服务器,如 kafka)等。

下载 Redis 并配置环境变量

官网 :https://redis.io/

github https://github.com/microsoftarchive/redis

常用命令

存取字符串(strings)

redis-cli   //连接Redis
127.0.0.1:6379[2]> select 1   //选择数据库  一个16个 0-15
127.0.0.1:6379[1]> flushdb    //刷新(清空)数据库
//存取数据  以key-value形式 存取字符串
127.0.0.1:6379[1]> set test:count 1
OK
127.0.0.1:6379[1]> get test:count
"1"

//增加减少
127.0.0.1:6379[1]> incr test:count
(integer) 2
127.0.0.1:6379[1]> decr test:count
(integer) 1

存取哈希(hashes)

127.0.0.1:6379[1]> hset test:user id 1
(integer) 1
127.0.0.1:6379[1]> hset test:user username wangwu
(integer) 1

//获取相应值
127.0.0.1:6379[1]> hget test:user id
"1"
127.0.0.1:6379[1]> hget test:user username
"wangwu"

存取列表(lists)

127.0.0.1:6379[1]> lpush test:ids 101 102 103   //左端方式存入数据   最终结果为  103 102 101
(integer) 3
127.0.0.1:6379[1]> llen test:ids       //取列表长度
(integer) 3
127.0.0.1:6379[1]> lindex test:ids 0
"103"
127.0.0.1:6379[1]> lrange test:ids 0 2
1) "103"
2) "102"
3) "101"
127.0.0.1:6379> rpop test:ids    //从右端弹出一个数据 列表长度减一
"101"
127.0.0.1:6379> rpop test:ids
"102"
127.0.0.1:6379> rpop test:ids
"103"

存取集合(sets)

127.0.0.1:6379> sadd test:teachers aaa bbb ccc   //存入数据 aaa bbb ccc
(integer) 3
127.0.0.1:6379> scard test:teachers    //获取集长度
(integer) 3
127.0.0.1:6379> spop test:teachers         //随机弹出一个数据
"aaa"
127.0.0.1:6379> smembers test:teachers     //查询集合数据
1) "ccc"
2) "bbb"

存取有序集合(sorted sets)

127.0.0.1:6379> zadd test:students 10 aaa 20 bbb 30 ccc    //分数和姓名
(integer) 3
127.0.0.1:6379> zcard test:students       //统计有多少个数据
(integer) 3
127.0.0.1:6379> zscore test:students ccc
"30"
127.0.0.1:6379> zrank test:students ccc  //返回某一个值的排名 由小到大
(integer) 2
127.0.0.1:6379> zrank test:students aaa
(integer) 0
127.0.0.1:6379> zrange test:students 0 2
1) "aaa"
2) "bbb"
3) "ccc"

常用全局命令

127.0.0.1:6379> keys *    //查看所有的key
1) "test:ids"
2) "test:students"
3) "test:teachers"
127.0.0.1:6379> type test:ids    //看某一个key的类型
list
127.0.0.1:6379> exists test:user //是否存在某一个key
(integer) 0
127.0.0.1:6379> expire test:ids 10      //给key设置过期时间 /秒
(integer) 1
127.0.0.1:6379> keys *
1) "test:ids"
2) "test:students"
3) "test:teachers"
127.0.0.1:6379> keys *
1) "test:students"
2) "test:teachers"

注意点:

  1. Redis 的一些基本概念,NoSQL,快照日志等
  2. Redis 的五种常见的数据类型及其常用命令,以及常用的全局命令

Spring 整合 Redis

引入依赖 spring-boot-starter-data-redis

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

(不需要写版本,pom 父文件中定义了互相兼容的版本)

配置 Redis - 配置数据库参数 - 编写配置类,构造 RedisTemplate

# RedisProperties
spring.redis.database=11        //选择的库 一共16个 从0-15
spring.redis.host=localhost         //地址ip
spring.redis.port=6379       //端口

访问 Redis

编写 RedisConfig

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        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;
    }

}

通过 redisTemplate 访问 Redis

· redisTemplate.opsForValue()

@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));

}

· redisTemplate.opsForHash()

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

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

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

· redisTemplate.opsForList()

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

· redisTemplate.opsForSet()

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

· redisTemplate.opsForZSet()

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

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

    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().range(redisKey, 0, 4));

}

· 全局操作

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

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

    redisTemplate.expire("test:students", 10, TimeUnit.SECONDS);
}

· 把 key 绑定到一个对象上,不用多次传入 key

// 多次访问同一个key
@Test
public void testBoundOperations() {
    BoundValueOperations operations = redisTemplate.boundValueOps("test:count");
    // 利用绑定的对象操作
    operations.increment();
    operations.increment();
    operations.increment();
    operations.increment();
    operations.increment();
    System.out.println(operations.get());
}

 · 编程式事务

@Test
public void testTx() {
    Object obj = redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations operations) throws DataAccessException {
            String redisKey = "test:tx";

            operations.multi();

            operations.opsForSet().add(redisKey, "zhangsan");
            operations.opsForSet().add(redisKey, "lisi");
            operations.opsForSet().add(redisKey, "wangwu");

            System.out.println(operations.opsForSet().members(redisKey));
            return operations.exec();
        }
    });

    System.out.println(obj);    // [1, 1, 1, [zhangsan, lisi, wangwu]]
}

这里的 sout 输出为空,个人猜测是因为在 Java 代码的 multi 和 exec 之间的所有 Redis 命令被 Redis 加到事务执行命令队列,但是 Java 代码这个时候就已经被执行了,但是 members 那条命令不回立刻返回结果,所以这个时候 sout 拿不到结果就输出空。到最后 exec,Redis 把队列里的命令都执行了,返回一个结果,最后打印出来。感觉就是把 multi 和 exec 之间的 Redis 命令抽取出来了。(不一定对)

注意点:

  1. Autowired 的时候,参数名需要和 Bean 的名字完全一样,否则会报错
  2. RedisConfig 的代码编写,注入连接工厂、设置序列化方式以及最后调用 afterPropertiesSet()
  3. 各种常见操作方法,包括绑定 key 的方法
  4. Redis 的事务特性(见上),multi、exec。

标签:127.0,仿牛,0.1,Redis,redisKey,6379,客网,test,redisTemplate
来源: https://www.cnblogs.com/CWZhou/p/16356310.html