1. The difference between Jedis, Redisson, and Lettuce
What they have in common: Both provide Java APIs based on Redis operations, but the degree of encapsulation and specific implementation are slightly different.
difference:
1.1、Jedis
is a client for the Java implementation of Redis. Support basic data types such as: String, Hash, List, Set, Sorted Set.
Features: Use blocking I/O, method calls are synchronous, the program flow needs to wait until the socket finishes processing the I/O to execute, and does not support asynchronous operations. Jedis client instances are not thread-safe and need to use Jedis through a connection pool.
1.2、Redisson
Advantages: Distributed locks, distributed collections, support delay queues through Redis.
1.3、 Lettuce
For thread-safe synchronous, asynchronous and reactive usage, with support for clusters, Sentinel, pipes and encoders.
An event-driven communication layer based on the Netty framework, whose method calls are asynchronous. Lettuce’s API is thread-safe, so you can operate a single Lettuce connection to complete various operations.
2. RedisTemplate
2.1, use configuration
Maven configuration import, (to add version number, I am here because Parent has declared)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
application-dev.yml
spring: redis: host: 192.168.1.140 port: 6379 password: database: 15 # Specify the sub-library of redis (a total of 16 0 to 15)
2.2, usage examples
@Resource private StringRedisTemplate stringRedisTemplate; @Override public CustomersEntity findById(Integer id) { // need cache // All involved caches need to be deleted, or updated try { String toString = stringRedisTemplate.opsForHash().get(REDIS_CUSTOMERS_ONE, id + "").toString(); if (toString != null) { return JSONUtil.toBean(toString, CustomersEntity.class); } } catch (Exception e) { e.printStackTrace(); } // When the cache is empty, check first, then cache redis Optional<CustomersEntity> byId = customerRepo.findById(id); if (byId. isPresent()) { CustomersEntity customersEntity = byId.get(); try { stringRedisTemplate.opsForHash().put(REDIS_CUSTOMERS_ONE, id + "", JSONUtil.toJsonStr(customersEntity)); } catch (Exception e) { e.printStackTrace(); } return customersEntity; } return null; }
2.3, extension
2.3.1, spring-boot-starter-data-redis dependency package
3.3.2, stringRedisTemplate API (partial display)
-
opsForHash –> hash operation
-
opsForList –> list operation
-
opsForSet –> set operation
-
opsForValue –> string operation
-
opsForZSet –> Zset operation
3.3.3 StringRedisTemplate default serialization mechanism
public class StringRedisTemplate extends RedisTemplate<String, String> { /** * Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)} * and {@link #afterPropertiesSet()} still need to be called. */ public StringRedisTemplate() { RedisSerializer<String> stringSerializer = new StringRedisSerializer(); setKeySerializer(stringSerializer); setValueSerializer(stringSerializer); setHashKeySerializer(stringSerializer); setHashValueSerializer(stringSerializer); } }
3. RedissonClient operation example
3.1 Basic Configuration
3.1.1, Maven pom introduction
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>org.redisson redisson 3.8.2 true org.redisson redisson-spring-boot-starter LATEST
3.1.2, add configuration file Yaml or json format
redisson-config.yml
# Redisson configuration singleServerConfig: address: "redis://192.168.1.140:6379" password: null clientName: null database: 15 #choose which database to use 0~15 idleConnectionTimeout: 10000 pingTimeout: 1000 connectTimeout: 10000 timeout: 3000 retryAttempts: 3 retryInterval: 1500 reconnectionTimeout: 3000 failedAttempts: 3 subscriptionsPerConnection: 5 subscriptionConnectionMinimumIdleSize: 1 subscriptionConnectionPoolSize: 50 connectionMinimumIdleSize: 32 connectionPoolSize: 64 dnsMonitoringInterval: 5000 #dnsMonitoring: false threads: 0 nettyThreads: 0 codec: class: "org.redisson.codec.JsonJacksonCodec" transportMode: "NIO"
Alternatively, configure redisson-config.json
{ "singleServerConfig": { "idleConnectionTimeout": 10000, "pingTimeout": 1000, "connectTimeout": 10000, "timeout": 3000, "retryAttempts": 3, "retryInterval": 1500, "reconnectionTimeout": 3000, "failedAttempts": 3, "password": null, "subscriptionsPerConnection": 5, "clientName": null, "address": "redis://192.168.1.140:6379", "subscriptionConnectionMinimumIdleSize": 1, "subscriptionConnectionPoolSize": 50, "connectionMinimumIdleSize": 10, "connectionPoolSize": 64, "database": 0, "dnsMonitoring": false, "dnsMonitoringInterval": 5000 }, "threads": 0, "nettyThreads": 0, "codec": null, "useLinuxNativeEpoll": false }
3.1.3, read configuration
New read configuration class
@Configuration public class RedissonConfig { @Bean public RedissonClient redisson() throws IOException { // Two reading methods, Config.fromYAML and Config.fromJSON // Config config = Config.fromJSON(RedissonConfig.class.getClassLoader().getResource("redisson-config.json")); Config config = Config.fromYAML(RedissonConfig.class.getClassLoader().getResource("redisson-config.yml")); return Redisson.create(config); } }
Or, configure it in application.yml as follows
spring: redis: redisson: config: classpath:redisson-config.yaml
3.2 Example of use
@RestController @RequestMapping("/") public class TeController { @Autowired private RedissonClient redissonClient; static long i = 20; static long sum = 300; // =========================== String ====================== == @GetMapping("/set/{key}") public String s1(@PathVariable String key) { // set the string RBucket<String> keyObj = redissonClient.getBucket(key); keyObj.set(key + "1-v1"); return key; } @GetMapping("/get/{key}") public String g1(@PathVariable String key) { // set the string RBucket<String> keyObj = redissonClient.getBucket(key); String s = keyObj. get(); return s; } // =========================== hash ====================== ==-= @GetMapping("/hset/{key}") public String h1(@PathVariable String key) { Ur ur = new Ur(); ur.setId(MathUtil.randomLong(1,20)); ur.setName(key); // Store Hash RMap<String, Ur> ss = redissonClient.getMap("UR"); ss. put(ur. getId(). toString(), ur); return ur.toString(); } @GetMapping("/hget/{id}") public String h2(@PathVariable String id) { // hash query RMap<String, Ur> ss = redissonClient.getMap("UR"); Ur ur = ss. get(id); return ur.toString(); } // query all keys @GetMapping("/all") public String all(){ RKeys keys = redissonClient. getKeys(); Iterable<String> keys1 = keys. getKeys(); keys1.forEach(System.out::println); return keys.toString(); } // ======================================== Read-write lock test ============ ================== @GetMapping("/rw/set/{key}") public void rw_set(){ //RedissonLock. RBucket<String> ls_count = redissonClient.getBucket("LS_COUNT"); ls_count.set("300",360000000l, TimeUnit.SECONDS); } // subtraction operation @GetMapping("/jf") public void jf(){ String key = "S_COUNT"; // RAtomicLong atomicLong = redissonClient.getAtomicLong(key); // atomicLong.set(sum); // long l = atomicLong.decrementAndGet(); // System.out.println(l); RAtomicLong atomicLong = redissonClient.getAtomicLong(key); if (!atomicLong.isExists()) { atomicLong.set(300l); } while (i == 0) { if (atomicLong. get() > 0) { long l = atomicLong. getAndDecrement(); try { Thread. sleep(1000l); } catch (InterruptedException e) { e.printStackTrace(); } i --; System.out.println(Thread.currentThread().getName() + "->" + i + "->" + l); } } } @GetMapping("/rw/get") public String rw_get(){ String key = "S_COUNT"; Runnable r = new Runnable() { @Override public void run() { RAtomicLong atomicLong = redissonClient.getAtomicLong(key); if (!atomicLong.isExists()) { atomicLong.set(300l); } if (atomicLong. get() > 0) { long l = atomicLong. getAndDecrement(); i --; System.out.println(Thread.currentThread().getName() + "->" + i + "->" + l); } } }; while (i != 0) { new Thread(r).start(); // new Thread(r). run(); // new Thread(r). run(); // new Thread(r). run(); // new Thread(r). run(); } RBucket<String> bucket = redissonClient.getBucket(key); String s = bucket. get(); System.out.println("================ thread has ended ========================== ==========" + s); return s; } }
4.3 Extension
4.3.1 Rich jar support, especially for Netty NIO framework
4.3.2 Rich selection of configuration mechanisms, here is the detailed configuration instructions
https://github.com/redisson/redisson/wiki/2.-Configuration
Regarding the serialization mechanism, there are many
4.3.3 API support (partial display), specific Redis –> RedissonClient, you can check here
https://github.com/redisson/redisson/wiki/11.-Redis-commands-mapping
4.3.4 Implementation of Portable and Rich Locking Mechanism
-
lock
-
Fair Lock
-
MultiLock
-
Red Lock
-
ReadWriteLock
-
Semaphore
-
PermitExpirableSemaphore
-
CountDownLatch
4. Redis cache based on annotation
4.1 Maven and YML configuration
Refer to RedisTemplate configuration. In addition, additional configuration classes are required
// todo defines serialization to solve the problem of garbled characters @EnableCaching @Configuration @ConfigurationProperties(prefix = "spring.cache.redis") public class RedisCacheConfig { private Duration timeToLive = Duration. ZERO; public void setTimeToLive(Duration timeToLive) { this.timeToLive = timeToLive; } @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // Solve the problem of query cache conversion exception ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // Configure serialization (to solve the problem of garbled characters) RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(timeToLive) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(config) .build(); return cacheManager; } }
4.2 Example of use
@Transactional @Service public class ReImpl implements RedisService { @Resource private CustomerRepo customerRepo; @Resource private StringRedisTemplate stringRedisTemplate; public static final String REDIS_CUSTOMERS_ONE = "Customers"; public static final String REDIS_CUSTOMERS_ALL = "allList"; // ================================================== ======================= Use Spring cahce annotations to implement caching // ====================================== Single operation @Override @Cacheable(value = "cache:customer", unless = "null == #result",key = "#id") public CustomersEntity cacheOne(Integer id) { final Optional<CustomersEntity> byId = customerRepo.findById(id); return byId.isPresent() ? byId.get() : null; } @Override @Cacheable(value = "cache:customer", unless = "null == #result", key = "#id") public CustomersEntity cacheOne2(Integer id) { final Optional<CustomersEntity> byId = customerRepo.findById(id); return byId.isPresent() ? byId.get() : null; } // todo custom redis cache key, @Override @Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id") public CustomersEntity cacheOne3(Integer id) { final Optional<CustomersEntity> byId = customerRepo.findById(id); return byId.isPresent() ? byId.get() : null; } // todo is cached in redis here, and the response page is String (with a lot of escape characters \,), not in Json format @Override @Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id") public String cacheOne4(Integer id) { final Optional<CustomersEntity> byId = customerRepo.findById(id); return byId.map(JSONUtil::toJsonStr).orElse(null); } // todo caches json, no garbled characters have been processed, adjust serialization and deserialization @Override @Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id") public CustomersEntity cacheOne5(Integer id) { Optional<CustomersEntity> byId = customerRepo.findById(id); return byId.filter(obj -> !StrUtil.isBlankIfStr(obj)).orElse(null); } // ========================================================================================= all cache @Override @CacheEvict(value = "cache:customer", key = "'cacheOne5' + '.' + #id") public Object del(Integer id) { // Logic after deleting the cache return null; } @Override @CacheEvict(value = "cache:customer",allEntries = true) public void del() { } @CacheEvict(value = "cache:all",allEntries = true) public void delall() { } // ===================List operation @Override @Cacheable(value = "cache:all") public List<CustomersEntity> cacheList() { List<CustomersEntity> all = customerRepo. findAll(); return all; } // todo queries the cache first, then checks whether it is consistent, and then updates the operation, which is more practical. It is necessary to know the data format of the cache (clear business and cache model data) @Override @CachePut(value = "cache:all",unless = "null == #result",key = "#root.methodName") public List<CustomersEntity> cacheList2() { List<CustomersEntity> all = customerRepo. findAll(); return all; } }
4.3 Extension
Implementation based on spring cache
Source: blog.csdn.net/qq_42105629/article/details/102589319
······················································
Data link
Self-taught Linux Notes from Tsinghua Senior Sister, Ceiling Level! The new version of "Illustrated Java" summarized by Mr. Ali's private kitchen information is popular, and the full version of PDF is open for download! Alibaba is officially launched! SpringBoot + SpringCloud full-color guide The strongest SpringBoot + Vue full-stack project ceiling in China, no rebuttals are accepted!
Welcome to add personal WeChat itcodexy into the fan group or watch the circle of friends