SpringBoot actual combat (20) | integration Redis

  Cache, mysql, redis, springboot

WeChat Public Number: An Outstanding Disabled Person. If you have any questions, please leave a message backstage. I won’t listen anyway.

Redis

Preface

I’m really ashamed that I haven’t updated the original for two months. There is no excuse, just because I am lazy. Recently, I read “Deliberate Learning”. This book talks about the relationship between learning and action. The book mentions the concept of “continuous action”, which means that we have to do something really and everyday to call it “continuous action”. After reading this book, I realized what I had to do, that is writing.

Redis introduction

Redis is an open source, memory-based key-value data store that serves as a database, cache, and message broker. In terms of implementation, the Key-Value store represents one of the largest and oldest members in the NoSQL space. Redis supports data structures such as strings, hashes, lists, sets, and ordered sets with range queries.
In the framework of spring data redis, it can be easily written by providing an abstract data store using Redis’ key-value store for Spring applications.
Non-relational database, based on memory, can not access data faster than relational database.
Redis is a database of key-value pairs

Data type

  • String type string
  • Hash type hash
  • List type list
  • Collection type set
  • Ordered set type zset

Among them, because the SpringBoot agreement is greater than the configuration feature, as long as we join the spring-data-redis dependency package and configure the Redis database, SpringBoot will help us to automatically configure a RedisTemplate. With it, we can operate the corresponding data types in the following ways. In the following actual combat, I will operate on these five types of data.

  • redisTemplate.opsForValue(); //operation string
  • redisTemplate.opsForHash(); //operate hash
  • redisTemplate.opsForList(); //operation list
  • redisTemplate.opsForSet(); //operation set
  • redisTemplate.opsForZSet(); //orderly set operation

development environment

  • SpringBoot 2.1.6 RELEASE
  • spring-data-redis 2.1.9 RELEASE
  • Redis 3.2
  • IDEA
  • JDK8
  • mysql

I won’t go into details about how to install Redis here, please search and solve by your own search engine.

Pom dependency

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>

Configuration file

spring:

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456

  jpa:
    hibernate:
      ddl-auto: update   #ddl-auto:设为 create 表示每次都重新建表
    show-sql: true

  redis:
    host: localhost
    port: 6379
    # Redis数据库索引(默认为0)
    database: 1
    jedis:
      pool:
        #连接池最大连接数
        max-active: 8
        #最小空闲连接
        min-idle: 0
        #最大阻塞等待时间,负值表示没有限制
        max-wait: -1ms
        #最大空闲连接
        max-idle: 8
    #连接超时时间(毫秒)
    timeout: 20ms
    # 无密码可不写
    # password:

Why is it scrambled?

    /**
     * 添加字符串
     */
    @Test
    public void setString(){
        redisTemplate.opsForValue().set(USERKEY,"nasus");
        redisTemplate.opsForValue().set(AGEKEY,24);
        redisTemplate.opsForValue().set(CITYKEY,"清远");
    }

The first is to add data of string type. The results of its operation are as follows:
添加字符串

How to Solve Random Codes

We can see that the inserted data is garbled, because the RedisTemplate automatically configured by SpringBoot does not set the serialization method of key and value when reading data. Therefore, we need to write our own RedisTemplate and set the serialization methods of key and value to operate Redis normally. As follows:

@Configuration
public class RedisConfig {

    private final RedisTemplate redisTemplate;

    @Autowired
    public RedisConfig(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Bean
    @SuppressWarnings("unchecked")
    public RedisTemplate<String, Object> redisTemplate() {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        //RedisSerializer<Object> jsonString = new GenericToStringSerializer<>(Object.class);
        RedisSerializer<Object> jsonString = new FastJsonRedisSerializer<>(Object.class);
        // String 的 key 和 hash 的 key 都采用 String 的序列化方式
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        // value 都采用 fastjson 的序列化方式
        redisTemplate.setValueSerializer(jsonString);
        redisTemplate.setHashValueSerializer(jsonString);
        return redisTemplate;
    }

}

At this time, run the above unit test again, and the result will be normal.

正常序列化结果

Action List

    /**
     * 添加、获取LIST
     */
    @Test
    public void setList(){
        List<Student> students = studentService.findStudentList();
        log.info("students size = {}", students.size());
        //循环向 studentList 左添加值
        students.forEach(value->redisTemplate.opsForList().leftPush(LISTKEY,value));
        //向 studentList 右添加值
        Student student = new Student();
        student.setId(10);
        student.setAge(24);
        student.setName("rightPush");
        redisTemplate.opsForList().rightPush(LISTKEY,student);
        // 获取值
        log.info("studentList->{}",redisTemplate.opsForList().range(LISTKEY,0,10));
    }

It should be mentioned here that the difference between leftpush and rightpush is that the former adds an element to the head of the list corresponding to key, which is what we often say comes later. the element with the largest subscript of List<Student > is in the first place in this list. The latter adds an element at the end of the list corresponding to key, which is exactly the opposite of the former.

Get the value, code here is 0 to 10 lines of data, console print results:

[{"name":"优秀","id":9,"age":22}, {"name":"冯某华","id":8,"age":25}, {"name":"蓝某城","id":7,"age":25}, {"name":"优秀","id":6,"age":22}, {"name":"冯某华","id":5,"age":25}, {"name":"蓝某城","id":4,"age":25}, {"name":"冯某华","id":3,"age":25}, {"name":"蓝某城","id":2,"age":25}, {"name":"废人","id":1,"age":22}, {"name":"rightPush","id":10,"age":24}]

Add List results:

添加 List

Note here that the id values of lines 1 to 9 are exactly the opposite, while under normal circumstances, the value I found from mysql data is as follows:
mysql 查询结果
Therefore, the difference between leftpush and rightpush is verified.

Operation set

    /**
     * 添加和获取Set
     */
    @Test
    public void setAndGetSet(){
        List<String> usernameList = new ArrayList<>();
        usernameList.add("nasus");
        usernameList.add("nasus");
        usernameList.add("一个优秀的废人");
        //循环向添加值
        usernameList.forEach(value->redisTemplate.opsForSet().add(SETKEY,value));
        log.info("取出usernameSet->{}",redisTemplate.opsForSet().members(SETKEY));
    }

    /**
     * 删除 Set
     */
    @Test
    public void delSet(){
        redisTemplate.opsForSet().remove(SETKEY,"nasus");
    }

Redis’s set data structure, like java’s hashset data structure, is unordered and does not repeat. So I added two nasus strings in my code, but actually I only added one nasus. The results are as follows:

添加 set

Operate hash

The addition, deletion and acquisition of hash are made respectively. The code is as follows: It needs to be explained here that the hash of hash has two keys that can be set, the first is the key in redis, and the second is the hashkey for each piece of data.

    /**
     * 添加 hash
     */
    @Test
    public void setHash(){
        List<Student> students = studentService.findStudentList();
        //添加
        for (Student student : students){
            redisTemplate.opsForHash().put(HASHKEY, student.getId().toString(), student);
        }
    }

    /**
     * 删除 hash
     */
    @Test
    public void delHash(){
        Student student = studentService.findStudentById(0);
        // 删除
        redisTemplate.opsForHash().delete(HASHKEY,JSON.toJSONString(student));
    }

    /**
     * 获取 Hash
     */
    @Test
    public void getHash(){
        List<Student> students = redisTemplate.opsForHash().values(HASHKEY);
        log.info("values = {}", students);
    }

Add hash result:

添加 hash

Get hash operation results:

获取 hash

Source address

https://github.com/turoDog/Demo/tree/master/springboot_redis_demo

Recommended reading

SpringBoot | automatic configuration principle

Postscript

If this article is of any help to you, please help me look good. Your good looks are my motivation to persist in writing.
In addition, after the attention is sent1024Free study materials are available.

For details, please refer to this old article:Python, C++, Java, Linux, Go, Front End, Algorithm Data Sharing

一个优秀的废人