This is the 22nd day of my participation in the August More Text Challenge

1. Introduction to the commonly used Redis client

After Spring Boot 2.x, support for Redis connections is supported by default.

Jedis API online site: tool.oschina.net/uploads/api…

Author. IO

Concept:

Jedis: is the old Redis Java implementation client, provides a more comprehensive Redis command support;

Redisson: Implemented distributed extensible Java data structures;

Lettuce: Advanced Redis client for thread-safe synchronization, asynchronous and response use, supporting clustering, Sentinel, pipes and encoders.

Advantages:

Jedis: provides the operation features of Redis comprehensively;

Redisson: to promote the separation of users’ concerns on Redis, and provide a lot of distributed related operation services, such as distributed lock and distributed collection, which can support delay queue through Redis;

Lettuce: a timedriven communication layer based on the Netty framework, whose method calls are asynchronous, and the Lettuce API is thread-safe, so you can manipulate a single Lettuce connection to perform various operations.

2. Spring Boot integrates Jedis

When we use Spring Boot to build microservices, in many cases we still need redis cache to cache some data and store some data accessed with high frequency. If we use Redis directly, it is more troublesome. Here, Jedis is used to realize Redis cache to achieve the purpose of efficient cache.

2.1 Introduction of Jedis dependencies

 <dependency>
     <groupId>redis.clients</groupId>
     <artifactId>jedis</artifactId>
 </dependency>
Copy the code

2.2 configuration application. Yml

Spring: redis: port: 6379 password: 2436 host: 112.124.1.187 Jedis: pool: max-idle: 6 # The maximum number of idle connections in the connection pool is 8. The default value is 8 min-idle. The default value is 0 timeout: 2000Copy the code

Spring Boot does not integrate Jedis, so you need to write your own configuration class to configure JedisPool

2.3 write Config

@Configuration public class JedisConfig { private Logger logger = LoggerFactory.getLogger(JedisConfig.class); @Value("${spring.redis.port}") private Integer port; @Value("${spring.redis.host}") private String host; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.jedis.pool.max-idle}") private Integer maxIdle; @Value("${spring.redis.jedis.pool.max-active}") private Integer maxActive; @Value("${spring.redis.jedis.pool.min-idle}") private Integer minIdle; @Value("${spring.redis.timeout}") private Integer timeout; @Bean public JedisPool jedisPool(){ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(maxIdle); jedisPoolConfig.setMinIdle(minIdle); jedisPoolConfig.setMaxTotal(maxActive); JedisPool jedisPool = new JedisPool(jedisPoolConfig,host,port,timeout,password); Logger. info("Jedis successfully connected :" + host + ":" + port); return jedisPool; }}Copy the code

2.4 Test 1: String

Requirement: the user enters a key to determine whether the data exists in Redis. If so, query it in Redis and return it. If not, query it in MySQL database, assign the result to Redis and return it

// userService. Java public interface UserService {/** * The user enters a key * to check whether the data exists in Redis * if so, query it in Redis and return * If not, query it in MySQL database and assign the result to Redis. Public String getString(String key); } = = = = = = = = = = = = = = = = = = = = = = = / / UserServiceImpl Java @ Service @ the Log / / equivalent to the Logger Logger = LoggerFactory.getLogger(JedisConfig.class); public class UserServiceImpl implements UserService { @Autowired JedisPool jedisPool; @Override public String getString(String key) { String value = ""; Jedis Jedis = jedispool.getResource (); If (jedis.exists(key)){// 2.1 exists in redis, value = jedis.get(key); Log.info (" Query data in Redis!" ); } else{value = "MySQL > select * from Redis; Log.info (" query MySQL data: "+ value); jedis.set(key,value); } // 3. Close the Jedis connection jedis.close(); return value; } } ======================= // UserController.java @Controller public class UserController { @Autowired UserService userService; @RequestMapping("/getString") @ResponseBody public String getString(String key){ return userService.getString(key); }}Copy the code

2.5 tools

// JedisUtil.java @Component public class JedisUtil { @Autowired private JedisPool jedisPool; Public Jedis getJedis(){return jedispool.getResource (); } public void close(Jedis Jedis){if(Jedis! =null){ jedis.close(); }}... }Copy the code

2.6 Test 2: String

Requirement: The user enters a Redis data and the key is valid for 30 seconds

// userService. Java public interface UserService {/** * Public String expireStr(String key,String Value); public String expireStr(String key,String Value); } = = = = = = = = = = = = = = = = = = = = = = = / / UserServiceImpl Java @ Service @ the Log / / equivalent to the Logger Logger = LoggerFactory.getLogger(JedisConfig.class); public class UserServiceImpl implements UserService { @Autowired JedisPool jedisPool; @Autowired JedisUtil jedisUtil; /** * Test String type * requirement: Public String expireStr(String Key,String Value){Jedis Jedis = jedisutil.getJedis (); if(! Jedis.exists (key) {// 1. Store data in Redis. // 2. Set the expiration time of this value jedis.expire(key,30); Log.info (" set "+ key +" duration to :30 seconds. ); Long time = jedis.ttl(key);} // 3. jedisUtil.close(jedis); Return "this" + key + ":" + value +" } } ======================= @RestController public class UserController { @Autowired UserService userService; @RequestMapping("/expireStr") public String expireStr(String key,String value){ return userService.expireStr(key,value);  }}Copy the code

2.7 Test 3: Hash

Requirement: Query user information by user ID

Check whether it exists in Redis:

If present, fetch it directly from Redis;

If not, fetch it from MySQL and store it in Redis

// User.java @Data @NoArgsConstructor @AllArgsConstructor public class User implements Serializable { private String id;  private String name; private Integer age; } ======================= public interface UserService {/** * Test Hash type * Requirement: Query user information based on user ID * Check whether the user exists in Redis first: Public User findById(String id); public User findById(String id); } = = = = = = = = = = = = = = = = = = = = = = = * / @ / * Hash test Service @ the Log / / equivalent to the Logger Logger. = LoggerFactory getLogger (JedisConfig. Class); public class UserServiceImpl implements UserService { @Autowired JedisPool jedisPool; @Autowired JedisUtil jedisUtil; @Override public User findById(String id) { String key = "user:" + id; // Entity class name :id Jedis Jedis = jedisutil.getJedis (); User user = null; If (jedis.exists(key)){// User = new user (); Map<String, String> map = jedis.hgetAll(key); user.setId(map.get("id")); user.setName(map.get("name")); user.setAge(Integer.parseInt(map.get("age"))); Log.info ("=================== "query data from Redis "); User = new user (id,"xiaojian",22); The info (" = = = = = = = = = = = = = = = = = = = "query data from a MySQL" + user); // Store Redis Map<String, String> Map = new HashMap<>(); map.put("id",user.getId()); map.put("name",user.getName()); map.put("age",user.getAge()+""); jedis.hmset(key,map); Log.info ("=================== saved in Redis "); } jedisUtil.close(jedis); return user; } } ======================= @RestController public class UserController { @Autowired UserService userService; @RequestMapping("/findById") public String findById(String id){ return userService.findById(id).toString(); }}Copy the code

3. Spring Boot 2.x integrate lettuce

Lettuce: Advanced Redis client for thread-safe synchronization, asynchronous and response use, supporting clustering, Sentinel, pipes and encoders.

A timedriven communication layer based on the Netty framework, whose method calls are asynchronous, and the Lettuce API is thread-safe, so you can manipulate a single Lettuce connection to perform various operations.

3.1 Importing Dependencies

<! The default is a Java client --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <! -- Redis relies on commons-pool, Commons -pool2</artifactId> </dependency> Commons -pool2</artifactId>Copy the code

3.2 Configuration File

Spring: redis: port: 6379 Password: 2436 host: 112.124.1.187 Lettuce: Pool: max-active: 10 max-idle: 6 min-idle: 2 max-wait: 1000 shutdown-timeout: 100Copy the code

3.3 configuration class

// Add using RedisTemplate template without writing, @configuration public class RedisConfig {@bean public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory factory){ RedisTemplate<String,Object> template = new RedisTemplate(); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // When the @bean annotation returns the RedisTemplate, At the same time configuration hashKey with hashValue serialization way / / key String serialization method template. SetKeySerializer (stringRedisSerializer); / / the value by Jackson's serialized way template. SetValueSerializer (jackson2JsonRedisSerializer); / / the hash key also USES String serialization way template. SetHashKeySerializer (stringRedisSerializer); / / the hash value by Jackson's serialized way template. SetHashValueSerializer (jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; }}Copy the code

3.3.1 Configuration Problems

@Bean public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory factory){ RedisTemplate<String,Object> template = new RedisTemplate(); template.setConnectionFactory(factory); / / * * * * * * to * * * * * * 2 GenericJackson2JsonRedisSerializer GenericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); / / Jackson format Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer (Object. The class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); / / method expired, change 1 comment out here, normal or change 2 when using the / / om. EnableDefaultTyping (ObjectMapper. DefaultTyping. NON_FINAL); Change / / * * * * * * 1 * * * * * *, om. Other cases commented activateDefaultTyping (LaissezFaireSubTypeValidator. Instance); jackson2JsonRedisSerializer.setObjectMapper(om); // String format StringRedisSerializer StringRedisSerializer = new StringRedisSerializer(); // When the @bean annotation returns the RedisTemplate, At the same time configuration hashKey with hashValue serialization way / / key String serialization method template. SetKeySerializer (stringRedisSerializer); / / the value by Jackson's serialized way, use 2 * * * * * * * to * * * * * object template. SetValueSerializer (genericJackson2JsonRedisSerializer); / / the hash key also USES String serialization way template. SetHashKeySerializer (stringRedisSerializer); // The hash value uses Jackson's serialization, Use * * * * * * to * * * * * * 2 object template. SetHashValueSerializer (genericJackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; }Copy the code

Hash data type

  1. The original configuration file results (as shown by RedisDesktopManager) :
[" com. Xiaojian. Pojo. User ", {" id ":" 1103 ", "name" : "mind", "age" : 22}]Copy the code
  1. Change 1
{" id ":" 1105 ", "name" : "mind", "age" : 22}Copy the code
  1. Change to 2
{@ "class" : "com. Xiaojian. Pojo. User", "id" : "1106", "name" : "mind", "age" : 22}Copy the code

3.4 test

======== @Service @Slf4j public class UserServiceImpl { @Autowired private RedisTemplate<String,Object> redisTemplate; public String getString(){ System.out.println(redisTemplate); The info (RedisTemplate "-- -- -- -- -- -- -- -- - > test"); return null; } } ========== @SpringBootTest class BootLettuceApplicationTests { @Autowired private UserServiceImpl userService; @Test void contextLoads() { userService.getString(); }}Copy the code

PS: The Chinese characters queried in Linux are displayed in hexadecimal format. You can log in to the client by adding –raw after redis-cli

 [root@xiaojian bin]# ./redis-cli -a 2436 --raw
Copy the code

3.5 Test 1: String

Requirement: the user enters a key to determine whether the data exists in Redis. If so, query it in Redis and return it. If not, query it in MySQL database, assign the result to Redis and return it

@Service @Slf4j public class UserServiceImpl { @Autowired private RedisTemplate<String,Object> redisTemplate; /** * Lettuce --> RedisTemplate RedisTemplate RedisTemplate The user enters a key * to check whether the data exists in Redis * if so, query it in Redis and return * If not, query it in MySQL database and assign the result to Redis. Return * * @return */ public String getString(String key){String val = ""; if(redisTemplate.hasKey(key)){ // exist val = (String) redisTemplate.opsForValue().get(key); Log.info ("-----> retrieve data from Redis :" + val); } else{val = 1; Log.info ("-----> query data from MySQL :" + val); redisTemplate.opsForValue().set(key,val); Log.info ("-----> save data from MySQL to Redis"); } return val; } } ======================= @SpringBootTest class BootLettuceApplicationTests { @Autowired private UserServiceImpl userService; @Test void contextLoads() { String result = userService.getString("lettuce"); System.out.println(result); }}Copy the code

3.6 Test 2: String

Requirement: The user enters a Redis data and the key is valid for 30 seconds

@Service @Slf4j public class UserServiceImpl { @Autowired private RedisTemplate<String,Object> redisTemplate; /** * Test String type * requirement: The user enters a redis data, The key is valid for 20 hours * @ return * / public void expireStr (String key, String value) {redisTemplate. OpsForValue (). The set (key, value); Redistemplate. expire(key,20, timeunit.hours); redistemplate. expire(key,20, timeunit.hours); } } ================ @SpringBootTest class BootLettuceApplicationTests { @Autowired private UserServiceImpl userService;  @test void t2() {userservice.expirestr ("timeout"," timeout! "); ); }}Copy the code

3.7 Test 3: Hash (ID must be a string)

Requirement: Query user information by user ID

Check whether it exists in Redis:

If present, fetch it directly from Redis;

If not, fetch it from MySQL and store it in Redis

// First, add the hash serialization configuration in the RedisConfig class... / / the hash key also USES String serialization way template. SetHashKeySerializer (stringRedisSerializer); / / the hash value by Jackson's serialized way template. SetHashValueSerializer (jackson2JsonRedisSerializer); . ================ @Service @Slf4j public class UserServiceImpl { @Autowired private RedisTemplate<String,Object> redisTemplate; /** * test Hash * @param id * @return ** query user object information based on id * check whether the key exists in Redis * if not, query MySQL database and add result to Redis. Public User findById(String id){User User = null; If (redistemplate.opsForhash ().haskey ("user",id)){log.info("-----> fetch data from Redis!" ); user = (User)redisTemplate.opsForHash().get("user",id); } else{// get data from MySQL user = new user (); user.setId(id); User. Elegantly-named setName (" mind "); user.setAge(22); Log.info ("-----> fetch data from MySQL "); /** @param h user entity, user@param hv whole object */ redistemplate.opsForHash ().put("user",id,user); Log.info ("-----> Store map data in Redis "); } return user; } } ======================== @SpringBootTest class BootLettuceApplicationTests { @Autowired private UserServiceImpl userService; @Test void t3() { User user = userService.findById("1143"); System.out.println(user); }}Copy the code

PS: the problem

Problem 1: Many of the same strings appear —- > extracted

Solution 1: Utility classes

Solution 2: The entity Bean declares a method that returns a string of this class

Problem 2: Casting problems and rewriting long sections of redistemplate.opsForHash ()

Solution: Declare a variable at the top of the business class and replace the variable name with redistemplate.opsForHash ()

     @Resource(name = "redisTemplate")
     private ValueOperations<String, String> redisString;
 
     @Resource(name = "redisTemplate")
     private HashOperations<String, String, User> redisHash;    // K:"user"; HK:"ID"; HV: Object
Copy the code

4. Common application of Redis

4.1 Mobile phone Authentication function

Requirements:

Users enter their mobile phone number on the client and click send to generate a four-digit code valid for 60 seconds

Enter the verification code and click Verify to return success or invalid. Each mobile phone number can only be verified three times within five minutes. And give corresponding information prompt

4.2 Limiting the Login Function

Requirements:

A user is allowed to enter incorrect passwords only five times within two minutes.

If the number of login times exceeds, the login time is limited to one hour. (Each login failure is required to give the corresponding prompt)