Practice of redis operation in Java_ 03

Redis client

summary

redis is a distributed cache database with C/S architecture. It has its own command-line client and corresponding Java or other language clients. redis can be read and written through some API s in these clients.

preparation

Step 1: create a project.

Create a maven parent project, such as 03 redis, and create two sub projects under this project, one is SCA jedis and the other is SCA temporary, for example:

Step 2: add parent project dependency

Modify parent project POM XML file, adding compilation configuration

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

Basic application of Jedis

brief introduction

Jedis is a client operating redis in Java, which is similar to accessing mysql database through jdbc.

preparation

Add the following dependencies to the SCA jedis project

<dependencies>
 <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.5.2</version>
 </dependency>

 <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
 </dependency>

 <dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
 </dependency>
<dependencies>

Basic application practice of jeds

Create a unit test class in the src/test/java directory in the Jedis project, for example:

package com.jt;

import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.concurrent.TimeUnit;

public class JedisTests {

    @Test
    public void testGetConnection(){
        //If you can't connect, comment out redis Bind 127.0 in conf 0.1,
        //Change the protected mode value to no, then restart redis and try again
        Jedis jedis=new Jedis("192.168.126.130",6379);
        //jedis.auth("123456");// If in redis The password is set in conf
        String ping = jedis.ping();
        System.out.println(ping);
    }

    //String type exercise
    @Test
    public void testStringOper() throws InterruptedException {
        //Link (link with redis)
        Jedis jedis=new Jedis("192.168.126.130",6379);
        //Stored data (key/value)
        jedis.set("count","1");
        jedis.set("id","10001");
        jedis.set("content","aaaaaaaadfas");
        //Update data
        jedis.expire("id",1);//Set the effective duration of the key
        jedis.incr("count");//Automatically increment the value of the key
        //get data
        String count = jedis.get("count");
        //TimeUnit is an enumeration type in Java, SECONDS is an instance of enumeration type, and the underlying sleep will call thread Sleep() method
        //TimeUnit.SECONDS.sleep(1);// Sleep for one second
        Thread.sleep(1000);
        String id=jedis.get("id");
        Long num=jedis.strlen("content");
        System.out.println("cart.count="+count);
        System.out.println("id="+id);
        System.out.println("num="+num);
        //Release resources
        jedis.close();
    }
//json data exercise
@Test
 public void testJsonOper(){
     //Build object
      Map<String,Object> map=new HashMap<>();
      map.put("id",100);
      map.put("title","spring authentication");
      map.put("content","very good");
     //Convert object to json format string
      Gson gson=new Gson();
      String jsonStr=gson.toJson(map);
      //Write json string to redis
      Jedis jedis=new Jedis("192.168.126.128",6379);
      jedis.set("user",jsonStr);
      //Read data in redis
      jsonStr=jedis.get("user");
      System.out.println(jsonStr);
      Map<String,Object> obj=gson.fromJson(jsonStr,Map.class);
      System.out.println(obj);
      jedis.close();
 }
//hash type exercise
  @Test
  public void testHashOper01(){
        //1. Establish connection
        Jedis jedis=new Jedis("192.168.126.130",6379);
        //2. Store object information based on hash type
        jedis.hset("member","id","101");
        jedis.hset("member","username","jack");
        jedis.hset("member","mobile","3333333");
        //3. Update the data stored in hash type
        jedis.hset("member","username","tony");
        //4. Get hash type data information
        String username=jedis.hget("member","username");
        String mobile = jedis.hget("member", "mobile");
        System.out.println(username);
        System.out.println(mobile);
        //5. Release resources
        jedis.close();
    }
//hash type exercise (storing map objects directly)
@Test
public void testHashOper02(){
    //1. Establish connection
    Jedis jedis=new Jedis("192.168.126.130",6379);
    //2. Store a blog message
    Map<String,String> map=new HashMap<>();
    map.put("x","100");
    map.put("y","200");
    jedis.hset("point",map);
    //3. Get blog content and output it
    map=jedis.hgetAll("point");
    System.out.println(map);
    //4. Release resources
    jedis.close();
}
   /**
     * Test: application of list structure in redis
     * Based on FIFO(First In First Out) algorithm, a queue is implemented with redis
     */
    @Test
    public void testListOper01(){
        //1. Establish connection
        Jedis jedis=new Jedis("192.168.126.130",6379);
        //2. Store data
        jedis.lpush("lst1","A","B","C","C");
        //3. Update data
        Long pos=jedis.lpos("lst1","A");//Gets the location of the A element
        jedis.lset("lst1",pos,"D");//Change the content of the A element position to D
        //4. Obtain data
        int len=jedis.llen("lst1").intValue();//Gets the number of elements in the lst1 list
        List<String> rpop = jedis.rpop("lst1",len);//Gets all elements in the lst1 list
        System.out.println(rpop);
        //5. Release resources
        jedis.close();
    }



//list type exercise: implementing a blocking queue

@Test
public void testListOper02(){
    //1. Connect to redis
    Jedis jedis=new Jedis("192.168.126.128",6379);
    //2. Save data to the queue
    //jedis.lpush("list1","A","B","C");
    //3. Fetch data from the queue in first in first out order
    List<String> list= jedis.brpop(40,"list1");
    System.out.println(list);
    jedis.brpop(40,"list1");
    jedis.brpop(40,"list1");
    jedis.brpop(40,"list1");
    //4. Release resources
    jedis.close();
}
//set type exercise
@Test
public void testSetOper01() {
    //1. Connect to redis
    Jedis jedis = new Jedis("192.168.126.128", 6379);
    //2. Circle praise from friends
    jedis.sadd("count", "1", "1", "2");
    //3. Take out the number of likes
    Set<String> set = jedis.smembers("count");
    System.out.println(set);
    //4. Release resources
    jedis.close();
}
}

 

Connection pool JedisPool connection pool application

When we access redis directly based on Jedis, every time we get a connection and release the connection, it will bring great performance overhead. We can reuse the created connection with the help of Jedis connection pool to improve its performance. The simple application methods are as follows:

package com.jt;

import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


public class JedisPoolTests {
    @Test
   public void testJedisPool(){
        //Define the configuration of the connection pool
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(1000);//maximum connection
        config.setMaxIdle(60);//Maximum idle
        //Create connection pool
        JedisPool jedisPool=
        new JedisPool(config,"192.168.126.130",6379);
        //Get a connection from the pool
        Jedis resource = jedisPool.getResource();
        resource.auth("123456");
        //Accessing data via jedis connection
        resource.set("class","cgb2004");
        String clazz=resource.get("class");
        System.out.println(clazz);
        //Return link to pool
        resource.close();
        //Close connection pool
        jedisPool.close();
    }
}

We can design a data source based on the pool object. In the future, we can obtain connections from the pool through a data source object in the business. We don't need to create a pool object every time we obtain connections, for example:

package com.jt.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisDataSource {

    private static final String IP="192.168.126.128";
    private static final int PORT=6379;//redis.conf default port
    /**
     * volatile Keys are often used to decorate attributes:
     * 1)Ensure thread visibility (when one thread is changed, other CPU threads are immediately visible)
     * 2)Prohibit instruction reordering 
     * 3)Atomicity cannot be guaranteed (thread safety is not guaranteed)
     */
    private static volatile JedisPool jedisPool;
    //Scheme 1: creation of starving pool object
    /*static{
        JedisPoolConfig config=new JedisPoolConfig();
        config.setMaxTotal(16);
        config.setMaxIdle(8);
        jedisPool=new JedisPool(config,IP,PORT);
    }
    public static Jedis getConnection(){
        return jedisPool.getResource();
    }*/
    //Scheme 2: creation of lazy pool object
    public static Jedis getConnection(){
        if(jedisPool==null) {
            synchronized (JedisDataSource.class) {
                if (jedisPool == null) {
                    JedisPoolConfig config = new JedisPoolConfig();
                    config.setMaxTotal(16);
                    config.setMaxIdle(8);
                    jedisPool = new JedisPool(config, IP, PORT);
                    //Create object analysis
                    //1. Open up memory space
                    //2. Perform default initialization of attributes
                    //3. Execution construction method
                    //4. Assign the memory address of the created object to the jedisPool variable
                    //If you use volatile to modify the jedisPool variable, you can ensure that the above steps are executed in sequence
                }
            }
        }
        return jedisPool.getResource();
    }
    public static void close(){
        jedisPool.close();
    }
}

RedisTemplate basic application

brief introduction

RedisTemplate is a Java object for operating redis database in SpringBoot project. This object encapsulates some basic operations on redis.

preparation

Step 1: add dependency in SCA template project

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

Step 2: create the project configuration file application YML, which reads as follows:

spring:
  redis:
    host: 192.168.64.129  #Write your own ip address
    port: 6379

Step 3: create a project startup class, for example:

package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisApplication.class,args);
    }
}

RedisTemplate object application practice

RedisTemplate is an object specially used to operate remote redis data. By default, JDK serialization will be used to access data. The application case is as follows:

package com.jt.redis;
@SpringBootTest
public class RedisTemplateTests {
    //This object has been configured in the RedisAutoConfiguration class of the springboot project
    //This object uses the JDK serialization method by default when accessing data based on redis
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * Test string data access
     */
    @Test
    void testStringOper01(){
        //Specify the key/value serialization method yourself
        ValueOperations vo = redisTemplate.opsForValue();
        //key and value are stored in JDK serialization by default
        vo.set("token", UUID.randomUUID().toString());
        Object token = vo.get("token");
        System.out.println(token);
    }
    /**This method is used to operate the hash data in redis*/
    @Test
    void testHashOper(){
        HashOperations hashOperations = redisTemplate.opsForHash();//hash
        Map<String,String> blog=new HashMap<>();
        blog.put("id", "1");
        blog.put("title", "hello redis");
        hashOperations.putAll("blog", blog);
        hashOperations.put("blog", "content", "redis is very good");
        Object hv=hashOperations.get("blog","id");
        System.out.println(hv);
        Object entries=hashOperations.entries("blog");
        System.out.println("entries="+entries);
    }
    @Test
    void testListOper(){
      //Put data into the list set
        ListOperations listOperations = redisTemplate.opsForList();
        listOperations.leftPush("lstKey1", "100"); //lpush
        listOperations.leftPushAll("lstKey1", "200","300");
        listOperations.leftPush("lstKey1", "100", "105");
        listOperations.rightPush("lstKey1", "700");
        Object value= listOperations.range("lstKey1", 0, -1);
        System.out.println(value);
      //Fetch data from list set
        Object v1=listOperations.leftPop("lstKey1");//lpop
        System.out.println("left.pop.0="+v1);
        value= listOperations.range("lstKey1", 0, -1);
        System.out.println(value);
    }

    @Test
    void testSetOper(){
        SetOperations setOperations=redisTemplate.opsForSet();
        setOperations.add("setKey1", "A","B","C","C");
        Object members=setOperations.members("setKey1");
        System.out.println("setKeys="+members);
        //........
    }

   @Test
    void testFlushdb(){
        redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
               //redisConnection.flushDb();
                redisConnection.flushAll();
                return "flush ok";
            }
        });
    }

}

Application practice of StringRedisTemplate object

StringRedisTemplate is a special RedisTemplate object. It accesses data based on string serialization by default. Its application method is as follows:

package com.jt.redis;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@SpringBootTest
public class StringRedisTemplateTests {
    /**
     * This object is a client object that operates redis
     * String serialization (StringRedisSerializer) is adopted for key/value
     * To read and write redis data
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void testHashOper01(){
       //1. Get the object of hash operation
        HashOperations<String, Object, Object> vo =stringRedisTemplate.opsForHash();
       //2. Read and write redis data
       //2.1 storing an object
       vo.put("user", "id", "100");
       vo.put("user", "username", "tony");
       vo.put("user", "status", "1");
       //2.2 get an object
       //2.2. 1 get a property value of an object
       Object status =vo.get("user","status");
       System.out.println(status);
        //2.2. 2 get all the values corresponding to a key of the object
       List<Object> user = vo.values("user");
       System.out.println(user);
    }
    @Test
    void testStringOper02() throws JsonProcessingException {
        //1. Get string operation object (ValueOperations)
        ValueOperations<String, String> vo =
                stringRedisTemplate.opsForValue();
        //2. Read and write data in redis
        Map<String,String> map=new HashMap<>();
        map.put("id","100");
        map.put("title","StringRedisTemplate");
        //Convert the map object into a json string and write it to the redis database
        String jsonStr=//Jackson (included in spring boot starter web dependency)
        new ObjectMapper().writeValueAsString(map);
        vo.set("blog", jsonStr);
        jsonStr=vo.get("blog");
        System.out.println(jsonStr);
        //Convert json string to map object
        map=
        new ObjectMapper().readValue(jsonStr, Map.class);
        System.out.println(map);
    }
    @Test
    void testStringOper01(){
        //1. Get string operation object (ValueOperations)
        ValueOperations<String, String> vo =
                stringRedisTemplate.opsForValue();
        //2. Read and write data in redis
        vo.set("x", "100");
        vo.increment("x");
        vo.set("y", "200", 1, TimeUnit.SECONDS);
        String x = vo.get("x");
        String y = vo.get("y");
        System.out.println("x="+x+",y="+y);
    }
    @Test
    void testGetConnection(){
        RedisConnection connection =
                stringRedisTemplate.getConnectionFactory()
                        .getConnection();
        String ping = connection.ping();
        System.out.println(ping);
    }

}

Customize RedisTemplate object based on business (expansion)

We know that the RedisTemplate in the system adopts the JDK serialization mechanism by default. If we don't want to use the default JDK serialization method, we can customize the RedisTemplate object and specify our own serialization method, for example:

package com.jt;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.net.UnknownHostException;

@Configuration
public class RedisConfig {//RedisAutoConfiguration
    //Custom json serialization
    public RedisSerializer jsonSerializer(){
        //1. Define Redis serialization and deserialization specification objects (the underlying object completes object serialization and deserialization through ObjectMapper)
        Jackson2JsonRedisSerializer serializer=
                new Jackson2JsonRedisSerializer(Object.class);
        //2. Create an objectmapper (provided by jackson api library) object, and serialize and deserialize based on this object
        //2.1 creating ObjectMapper objects
        ObjectMapper objectMapper=new ObjectMapper();
        //2.2 set which method rules are used for serialization
        objectMapper.setVisibility(PropertyAccessor.GETTER,//get method
                 JsonAutoDetect.Visibility.ANY);//Any represents an arbitrary method access modifier
        //When the object property value is null, serialization storage is not performed
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //2.2 activate serialization type storage. When serializing an object, the object type will also be stored in redis database
        //Without this configuration, redis does not store types when storing data, and its data will be stored in map by default during deserialization
        objectMapper.activateDefaultTyping(
                objectMapper.getPolymorphicTypeValidator(),//Polymorphism check analysis
                ObjectMapper.DefaultTyping.NON_FINAL,//Activate serialization type storage, and the class cannot use final decoration
                JsonTypeInfo.As.PROPERTY);//PROPERTY representation types are stored as json object properties
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }
    //Advanced customization
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        //Set the serialization method of the key
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        //Sets how values are serialized
        template.setValueSerializer(jsonSerializer());
        template.setHashValueSerializer(jsonSerializer());
        //Update the default configuration of RedisTemplate object
        template.afterPropertiesSet();
        return template;
    }

    //Simple customization
//    @Bean
//    public RedisTemplate<Object, Object> redisTemplate(
//            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//        RedisTemplate<Object, Object> template = new RedisTemplate();
//        template.setConnectionFactory(redisConnectionFactory);
//        //Set the serialization method of the key
//        template.setKeySerializer(RedisSerializer.string());
//        template.setHashKeySerializer(RedisSerializer.string());
//        //Sets how values are serialized
//        template.setValueSerializer(RedisSerializer.json());
//        template.setHashValueSerializer(RedisSerializer.json());
//        return template;
//    }
}

Create a Blog object, and then serialize it based on RedisTemplate. The Blog code is as follows

package com.jt.redis.pojo;

import java.io.Serializable;

public class Blog implements Serializable {//{"id":10,"title":"redis"}
    private static final long serialVersionUID = -6721670401642138021L;
    private Integer id;
    private String title;
    public Blog(){
        System.out.println("Blog()");
    }
    public Blog(Integer id,String title){
        this.id=id;
        this.title=title;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
    @Override
    public String toString() {
        return "Blog{" +
                "id=" + id +
                ", title='" + title + '\'' +
                '}';
    }
}

Add the following unit test methods in RedisTemplateTests class to test, for example:

@Test
void testJsonOper() throws JsonProcessingException {
    ValueOperations valueOperations = redisTemplate.opsForValue();
    Blog blog=new Blog(10,"study redis");
    valueOperations.set("blog",blog);//serialize
    blog=(Blog)valueOperations.get("blog");//Deserialization
    System.out.println("blog="+blog);
}

Analysis and practice of project business based on Redis

Distributed id

Business description

In the distributed system, when the amount of data will be larger and larger, it is necessary to divide the data into tables. However, after dividing the tables, the data in each table will increase automatically according to its own rhythm, and there is likely to be id conflict. At this time, a separate mechanism is needed to generate unique IDs. The generated IDS can also be called distributed IDS. Here, we implement a simple distributed id with the help of redis. Of course, there are some third-party systems that can help you generate such IDs and expand your learning

Key code implementation

package com.jt.demos;

import redis.clients.jedis.Jedis;

/**
 * Requirement: generate an id with increasing distribution
 * Multiple tables use the id generated in this method as the primary key id value (the database will not be used in the distributed environment)
 * Self increment strategy in the table -auto_increment)
 */
public class IdGeneratorDemo01 {
    public static Long getId(){
          Jedis jedis=new Jedis("192.168.126.130",6379);
          //jedis.auth("123456");// If redis has set a password, you need to specify a password when connecting to redis
          Long id = jedis.incr("id");
          jedis.close();
          return id;
    }
    //Create your own thread to execute tasks
    static void execute01(){
         for(int i=0;i<10;i++) {
              new Thread(){
                  @Override
                  public void run() {
                      String tName=Thread.currentThread().getName();
                      System.out.println(tName+"->"+
                              IdGeneratorDemo01.getId());
                  }
              }.start();
          }
    }
     //Execute tasks based on thread pool  
     static void execute02(){
      //Build a thread pool with a maximum of 3 threads
        ExecutorService es=
        Executors.newFixedThreadPool(3);
        for(int i=1;i<=10;i++){
            //Fetch thread from pool to execute task
            es.execute(new Runnable() {//This task is stored in the blocking task queue
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()
                            +"->"+getId());
                }
            });
        }
    }
    public static void main(String[] args) {
        //execute01();
          execute02();
    }
}

Single sign on (SSO)

Business description

In a distributed system, there are multiple services. When we log in to one service and then access other services, we don't want to log in again. We usually call it a single sign on system. In this system, an authentication server is provided to complete user identity authentication. In some small and medium-sized distributed systems, We usually use redis to store user authentication information, such as:

Key code implementation

package com.jt.redis;

import redis.clients.jedis.Jedis;

import java.util.UUID;

/**
 * Design and implementation of single sign on based on redis
 * 1)After the user logs in successfully, the login status and other information will be stored in redis
 * 2)The user carries a token to access resources. The resource server should query user information from redis based on the token
 */
public class SSODemo01 {
    /**
     * Perform login authentication. In the future, such services will be written to the authentication server
     * @param username
     * @param password
     */
    static String doLogin(String username,String password){
       //1. Check the validity of the data (determine whether the user name and password are empty, the length of the password, and whether there are special symbols of numbers and letters)
       if(username==null||"".equals(username))
           throw new IllegalArgumentException("User cannot be empty");
       //2. Query user information based on user name and determine whether the password is correct
       if(!"jack".equals(username))
           throw new RuntimeException("This user does not exist");
       if(!"123456".equals(password))
           throw new RuntimeException("Incorrect password");
       //3. If the user exists and the password is correct, write the user information to redis
        Jedis jedis=new Jedis("192.168.126.128", 6379);
        String token= UUID.randomUUID().toString();
        jedis.hset(token, "username", username);
        jedis.hset(token, "permission", "sys:resource:create");
        jedis.expire(token, 10);//Set the effective time of the key
        jedis.close();
       //4. Return the token to the client (use the response object to respond to the client in the future)
        return token;
    }
    static String token;

    /**
     * Demonstrate resource access process
     * 1)Allow anonymous access (no login required)
     * 2)Access after login (authenticated)
     * 3)You must have permission to access after logging in
     */
    static Object doGetResource(String token){
        //1. Check whether the token is empty
        if(token==null)
            throw new IllegalArgumentException("Please log in first");
        //2. Query redis data based on token. If there is corresponding data, it indicates that the user has logged in
        Jedis jedis=new Jedis("192.168.126.128", 6379);
        String username=jedis.hget(token, "username");
        if(username==null)
            throw new RuntimeException("login timeout ,Please log in again");
        String permission=jedis.hget(token, "permission");
        jedis.close();
        //3. Check whether the user has permission to access resources. If yes, access is allowed
        if(!"sys:resource:create".equals(permission))
            throw new RuntimeException("You do not have permission to access this resource");
        //4. Return to the resource to be accessed
        return "your resource";
    }
    public static void main(String[] args) {
        //1. Login operation (user identity authentication)
        token=doLogin("jack", "123456");
        System.out.println(token);
        //2. Carry a token to access the resource server
        Object result=doGetResource(token);
        System.out.println(result);
    }
}

 

Simple spike queue

Business description

When designing a second kill or rush purchase system, in order to improve the response speed of the system, users' second kill or rush purchase requests are usually stored in a redis queue first. Here, we implement a first in first out queue based on redis, for example:

Key code implementation

package com.jt.demos;

import redis.clients.jedis.Jedis;

//Second kill queue demo
//In the description logic, the commodity rush purchase information will be written to redis first (stored in the form of queue),
//Because writing redis memory database is many times faster than writing your mysql database
//Algorithm: first in first out (FIFO) - reflect fairness
public class SecondKillDemo01 {

    //The first thing to rush to buy goods is to join the team
    static void enque(String msg){//Join the team
         Jedis jedis=new Jedis("192.168.126.130",6379);
         jedis.auth("123456");//There is no need to write this statement without authentication
         jedis.lpush("queue",msg);
         jedis.close();
    }

    //Bottom asynchronous queue out (generate orders, deduct inventory,... Based on this message)
    static String deque(){//Out of the team
        Jedis jedis=new Jedis("192.168.126.130",6379);
        jedis.auth("123456");//There is no need to write this statement without authentication
        String result=jedis.rpop("queue");
        jedis.close();
        return result;
    }
    public static void main(String[] args){
        //1. Multiple rush purchases (simulate multiple clicks on the interface)
        new Thread(){
            @Override
            public void run() {
                for(int i=1;i<=10;i++){//Click the button on the simulation page
                    enque(String.valueOf(i));
                    try{Thread.sleep(100);}catch(Exception e){}
                }
            }
        }.start();

        //2. Fetching content from the queue (simulating background fetching data from the queue)
        new Thread(){
            @Override
            public void run() {
                for(;;){
                    String msg=deque();
                    if(msg==null)continue;
                    System.out.print(msg);
                }
            }
        }.start();

    }
}

 

Simple voting system

Business description

In many system designs, there will be an activity design. Before starting an activity, you can conduct a survey on the support of the activity. For example, design a voting system based on the activity, such as:

Key code implementation

package com.jt.redis;

import redis.clients.jedis.Jedis;

import java.util.Set;

/**
 * Design of simple voting system based on an activity
 * 1)The voting data is stored in redis (the key is the activity id, a collection of multiple user IDs)
 * 2)The same user cannot vote more than once
 * 3)Specific business operations (voting, obtaining total votes, obtaining who participated in voting)
 */
public class VoteDemo01 {

    /**
     * Get votes on who has performed this activity
     * @param activityId
     * @return
     */
    static  Set<String> doGetMembers(String activityId){
        //1. Establish connection
        Jedis jedis=new Jedis("192.168.126.128", 6379);
        //2. Get the total number of votes for the current activity
        Set<String> smembers = jedis.smembers(activityId);
        //3. Release resources
        jedis.close();
        return smembers;
    }
    /**
     * Gets the total number of votes for the specified event
     * @param activityId
     * @return
     */
    static Long doCount(String activityId){
       //1. Establish connection
       Jedis jedis=new Jedis("192.168.126.128", 6379);
       //2. Get the total number of votes for the current activity
       Long count=jedis.scard(activityId);
       //3. Release resources
       jedis.close();
       return count;
    }
    /**
     * Execute voting operation
     * @param activityId
     * @param userId
     */
    static void doVote(String activityId,String userId){
       //1. Establish connection
        Jedis jedis=new Jedis("192.168.126.128", 6379);
       //2. Executive voting
        //2.1 check whether votes have been cast
        Boolean flag = jedis.sismember(activityId, userId);
        //2.2 execution or cancellation of voting
        if(flag){
            //If you have already voted, you will cancel the vote if you vote again
            jedis.srem(activityId, userId);
        }else{
            //If no vote has been cast, the voting shall be carried out
            jedis.sadd(activityId, userId);
        }
       //3. Release resources
        jedis.close();
    }
    public static void main(String[] args) {
        String activityId="101";
        String userId1="1";
        String userId2="2";
        String userId3="3";
        //Execute voting action
        doVote(activityId, userId1);
        doVote(activityId, userId2);
        doVote(activityId, userId3);
        //Total number of votes obtained
        Long aLong = doCount(activityId);
        System.out.println(aLong);
        //Get members voting
        Set<String> members= doGetMembers(activityId);
        System.out.println(members);
    }

}

 

Simple shopping cart system

Business description

The simple shopping cart business design is shown in the figure:

Basic instruction operations, such as:

1)Add items to cart
hset  cart:101  2001  1
hset  cart:101  2002  1
hset  cart:101  2003  2
2)View shopping cart items
hgetall cart:101
3)Delete cart item
hdel cart:101 2003
4)Change the purchase quantity of an item in the shopping cart
hincrby cart:101 2002 2

 

Key code implementation

package com.jt.demos;

import redis.clients.jedis.Jedis;

import java.util.Map;

/**
 * Job: store shopping cart information based on redis
 */
public class CartDemo01 {

    public static void addCart(Long userId,Long productId,int num){
        //1. Establish redis link
        Jedis jedis=new Jedis("192.168.126.130",6379);
        jedis.auth("123456");
        //2. Add items to the shopping cart
        //hincrBy this function will automatically create a key when the key does not exist
        jedis.hincrBy("cart:" + userId, String.valueOf(productId),num);
        //3. Release the redis link
        jedis.close();
    }
    //View my shopping cart
    public static Map<String, String> listCart(Long userId){
        //1. Establish redis link
        Jedis jedis=new Jedis("192.168.126.130",6379);
        jedis.auth("123456");
        //2. View shopping cart items
        Map<String, String> map = jedis.hgetAll("cart:" + userId);
        //3. Release the redis link
        jedis.close();
        return map;
    }
    public static void main(String[] args) {
        //1. Add items to the shopping cart
        addCart(101L,201L,1);
        addCart(101L,202L,1);
        addCart(101L,203L,2);
        //2. View shopping cart items
        Map<String, String> map = listCart(101L);
        System.out.println(map);
    }

}

Integration of Redis and Aop technologies in SpringBoot project

Business description

Based on AOP and Redis technology, MySQL and data operation in Redis database are realized

Project preparation

Step 1: open the SCA template project and add dependencies (two) for accessing the MySql database

<!--mysql rely on-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!--mybatis plus (simplify mybatis operation)-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>

Step 2: modify the configuration file of SCA template project and add the configuration of connecting to mysql database

spring:
  datasource:
    url: jdbc:mysql:///jt-sso?serverTimezone=Asia/Shanghai&characterEncoding=utf8
    username: root
    password: root

Pojo logical object definition

Define a Menu object, and the user encapsulates TB_ Data in the Menu table, for example:

package com.jt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import org.springframework.data.annotation.Id;

import java.io.Serializable;

@TableName(value = "tb_menus")
public class Menu implements Serializable {
    private static final long serialVersionUID = -577747732166248365L;
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private String permission;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPermission() {
        return permission;
    }

    public void setPermission(String permission) {
        this.permission = permission;
    }

    @Override
    public String toString() {
        return "Menu{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", permission='" + permission + '\'' +
                '}';
    }
}

Design and implementation of Dao logical object

Create TB for operating in database_ Mapper object of data in the menu table, for example:

package com.jt.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.pojo.Menu;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MenuMapper extends BaseMapper<Menu> {
}

Design and implementation of Service logical object

Step 1: define the business interface used to process menu business, for example:

package com.jt.service;
import com.jt.pojo.Menu;
import java.io.Serializable;
public interface MenuService {
    /**
     * Find the menu object based on id, and check redis first. Redis does not check the database again
     * @param id
     * @return
     */
    Menu selectById(Long id);
    /**
     * Write a menu message to the table. At the same time, write the same data to redis
     * @param menu
     * @return
     */
    Menu insertMenu(Menu menu);
    /**
     * Update the data in the table, and update the data in redis at the same time
     * @param menu
     * @return
     */
    Menu updateMenu(Menu menu);
    //.....
}

Step 2: define the business interface implementation class for processing menu business,
In this implementation class, you can operate Redis cache based on RedisTemplate object, for example:

package com.jt.service;
import com.jt.dao.MenuMapper;
import com.jt.pojo.Menu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;

@Service
public class MenuServiceImpl implements MenuService{
    @Autowired
    private MenuMapper menuMapper;

   // @Autowired
   // private RedisTemplate redisTemplate;

    @Resource(name="redisTemplate")
    private ValueOperations valueOperations;//From spring Check this injection method in the official data project of Io
    /**
     * Query menu information based on id. requirements:
     * 1)Check redis first. Redis didn't check mysql
     * 2)Store the data queried from mysql in redis
     * @param id
     * @return
     */
    @Override
    public Menu selectById(Long id) {
        //ValueOperations valueOperations = redisTemplate.opsForValue();
        Object obj=valueOperations.get(String.valueOf(id));
        if(obj!=null){
            System.out.println("Get Data from redis");
            return (Menu)obj;
        }
        Menu menu=menuMapper.selectById(id);
        valueOperations.set(String.valueOf(id), menu, Duration.ofSeconds(120));
        return menu;
    }
    @Override
    public Menu insertMenu(Menu menu) {
        menuMapper.insert(menu);
       // ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set(String.valueOf(menu.getId()), menu, Duration.ofSeconds(120));
        return menu;
    }
    @Override
    public Menu updateMenu(Menu menu) {
        menuMapper.updateById(menu);
       // ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations.set(String.valueOf(menu.getId()), menu, Duration.ofSeconds(120));
        return menu;
    }
}

Step 3: define the business interface implementation class for processing menu business, operate redis cache based on AOP mode, and compare
Different from the Redis operation mode written in step 2, for example:

package com.jt.service;

import com.jt.dao.MenuMapper;
import com.jt.pojo.Menu;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class DefaultMenuService implements MenuService{
    @Autowired
    private MenuMapper menuMapper;

    /**
     * The method described by this annotation is a pointcut method. When this method is executed, the underlying layer will pass the AOP mechanism
     * First fetch the data from the cache. If there is a cache, it will be returned directly. If there is no cache, the data will be queried. Finally, the queried data will be returned
     * It will also store a copy to redis
     * @param id
     * @return
     */
    @Cacheable(value = "menuCache",key="#id")
    @Override
    public Menu selectById(Long id) {
        return menuMapper.selectById(id);
    }

    /**
     * CachePut Annotation means updating the cache
     * @param menu
     * @return
     */
    @CachePut(value = "menuCache",key="#menu.id")
    @Override
    public Menu insertMenu(Menu menu) {
         menuMapper.insert(menu);
         return menu;
    }

    @CachePut(value = "menuCache",key="#menu.id")
    @Override
    public Menu updateMenu(Menu menu) {
        menuMapper.updateById(menu);
        return menu;
    }
}

Note: to start the AOP cache application, you need to add @ EnableCaching annotation on the startup class:

Step 4: define the unit test class and test the cache application based on the unit test class For example:

package com.jt;

import com.jt.pojo.Menu;
import com.jt.service.MenuService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest
public class MenuServiceTests {
    @Autowired
    @Qualifier("defaultMenuService")
    //@Resource(name="defaultMenuService")
    private MenuService menuService;
    @Test
    void testSelectById(){
        Menu menu = menuService.selectById(1L);
        System.out.println(menu);
    }
    @Test
    void testUpdateMenu(){
        Menu menu = menuService.selectById(1L);
        menu.setName("select res");
        menuService.updateMenu(menu);
    }
    @Test
    void testInertMenu(){
        Menu menu = new Menu();
        menu.setName("insert res");
        menu.setPermission("sys:res:insert");
        menuService.insertMenu(menu);
    }
}

Step 5: change the serialization mode of redis data storage in AOP mode (if required by business) In fact, we should rely on
CacheManager object, for example:

package com.jt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

/**
 * The purpose of reconstructing the CacheManager object is to change the serialization and deserialization of redis in AOP mode
 */
@Configuration
public class CacheManagerConfig {
    /**
     * Refactoring CacheManager objects
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        //Define RedisCache configuration
        RedisCacheConfiguration cacheConfig=
                RedisCacheConfiguration.defaultCacheConfig()
        //Define the serialization method of the key
        .serializeKeysWith(
                RedisSerializationContext.
                   SerializationPair.fromSerializer(RedisSerializer.string()))
        //Defines how value is serialized
        .serializeValuesWith(
                RedisSerializationContext.SerializationPair
                .fromSerializer(RedisSerializer.json()));

        return  RedisCacheManager.builder(redisConnectionFactory)
               .cacheDefaults(cacheConfig)
               .build();//Builder mode (for the creation of complex objects, it is recommended to use this method to encapsulate the creation details of objects)
    }
}

After writing this object, you can conduct unit test again based on the method in MenuService to detect the storage of redis data

Design and implementation of Controller logic object

Step 1: define the Controller processing to process the client's request for menu data, for example:

package com.jt.controller;
import com.jt.pojo.Menu;
import com.jt.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/menu")
public class MenuController{
    @Autowired
    @Qualifier("defaultMenuService")
    private MenuService menuService;

    @GetMapping("/{id}")
    public Menu doSelectById(@PathVariable("id") Long id){
        return menuService.selectById(id);
    }
    @PutMapping
    public String doUpdate(@RequestBody Menu menu){
         menuService.updateMenu(menu);
         return "update ok";
    }
    @PostMapping
    public String doInsert(@RequestBody Menu menu){
        menuService.insertMenu(menu);
        return "insert ok";
    }
}

Step 2: open postman for access test Detect redis data storage and update

Summary

This chapter mainly analyzes and practices the methods of operating redis database and API Application in Java. The understanding of specific methods can be analyzed based on the results in practice and gradually strengthen memory.

Keywords: Java Database Redis Back-end Cache

Added by stevenheller7@gmail.com on Fri, 10 Dec 2021 05:35:32 +0200