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.