智能摘要文章源自JAVA秀-https://www.javaxiu.com/42212.html
使用阻塞的I/O,方法调用同步,程序流需要等到socket处理完I/O才能执行,不支持异步操作。Jedis客户端实例不是线程安全的,需要通过连接池来使用Jedis。用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作。文章源自JAVA秀-https://www.javaxiu.com/42212.html
原文约 2555 字 | 图片 9 张 | 建议阅读 6 分钟 | 评价反馈文章源自JAVA秀-https://www.javaxiu.com/42212.html
SpringBoot 操作 Redis的各种实现(以及Jedis、Redisson、Lettuce的区别比较)
小哈学Java 文章源自JAVA秀-https://www.javaxiu.com/42212.html
文章源自JAVA秀-https://www.javaxiu.com/42212.html
来源:blog.csdn.net/qq_42105629/article/details/102589319文章源自JAVA秀-https://www.javaxiu.com/42212.html
一、Jedis,Redisson,Lettuce三者的区别
共同点:都提供了基于Redis操作的Java API,只是封装程度,具体实现稍有不同。文章源自JAVA秀-https://www.javaxiu.com/42212.html
不同点:文章源自JAVA秀-https://www.javaxiu.com/42212.html
1.1、Jedis
是Redis的Java实现的客户端。支持基本的数据类型如:String、Hash、List、Set、Sorted Set。文章源自JAVA秀-https://www.javaxiu.com/42212.html
特点:使用阻塞的I/O,方法调用同步,程序流需要等到socket处理完I/O才能执行,不支持异步操作。Jedis客户端实例不是线程安全的,需要通过连接池来使用Jedis。文章源自JAVA秀-https://www.javaxiu.com/42212.html
1.2、Redisson
优点点:分布式锁,分布式集合,可通过Redis支持延迟队列。文章源自JAVA秀-https://www.javaxiu.com/42212.html
1.3、 Lettuce
用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。文章源自JAVA秀-https://www.javaxiu.com/42212.html
基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作。文章源自JAVA秀-https://www.javaxiu.com/42212.html
二、RedisTemplate
2.1、使用配置
maven配置引入,(要加上版本号,我这里是因为Parent已声明)文章源自JAVA秀-https://www.javaxiu.com/42212.html
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>
application-dev.yml文章源自JAVA秀-https://www.javaxiu.com/42212.html
spring: redis: host: 192.168.1.140 port: 6379 password: database: 15 # 指定redis的分库(共16个0到15)
2.2、使用示例
@Resource private StringRedisTemplate stringRedisTemplate; @Override public CustomersEntity findById(Integer id) { // 需要缓存 // 所有涉及的缓存都需要删除,或者更新 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(); } // 缓存为空的时候,先查,然后缓存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、扩展
2.3.1、spring-boot-starter-data-redis的依赖包
文章源自JAVA秀-https://www.javaxiu.com/42212.html
图片文章源自JAVA秀-https://www.javaxiu.com/42212.html
3.3.2、stringRedisTemplate API(部分展示)
opsForHash --> hash操作文章源自JAVA秀-https://www.javaxiu.com/42212.html
opsForList --> list操作文章源自JAVA秀-https://www.javaxiu.com/42212.html
opsForSet --> set操作文章源自JAVA秀-https://www.javaxiu.com/42212.html
opsForValue --> string操作文章源自JAVA秀-https://www.javaxiu.com/42212.html
opsForZSet --> Zset操作文章源自JAVA秀-https://www.javaxiu.com/42212.html
文章源自JAVA秀-https://www.javaxiu.com/42212.html
图片文章源自JAVA秀-https://www.javaxiu.com/42212.html
3.3.3 StringRedisTemplate默认序列化机制
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); } }
三、RedissonClient 操作示例
3.1 基本配置
3.1.1、Maven pom 引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.8.2</version> <optional>true</optional></dependency><dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>LATEST</version></dependency>
3.1.2、添加配置文件Yaml或者json格式
redisson-config.yml文章源自JAVA秀-https://www.javaxiu.com/42212.html
# Redisson 配置singleServerConfig: address: "redis://192.168.1.140:6379" password: null clientName: null database: 15 #选择使用哪个数据库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: falsethreads: 0nettyThreads: 0codec: class: "org.redisson.codec.JsonJacksonCodec"transportMode: "NIO"
或者,配置 redisson-config.json文章源自JAVA秀-https://www.javaxiu.com/42212.html
{ "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、读取配置
新建读取配置类文章源自JAVA秀-https://www.javaxiu.com/42212.html
@Configurationpublic class RedissonConfig { @Bean public RedissonClient redisson() throws IOException { // 两种读取方式,Config.fromYAML 和 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); }}
或者,在 application.yml中配置如下文章源自JAVA秀-https://www.javaxiu.com/42212.html
spring: redis: redisson: config: classpath:redisson-config.yaml
3.2 使用示例
@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) { // 设置字符串 RBucket<String> keyObj = redissonClient.getBucket(key); keyObj.set(key + "1-v1"); return key; } @GetMapping("/get/{key}") public String g1(@PathVariable String key) { // 设置字符串 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); // 存放 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 查询 RMap<String, Ur> ss = redissonClient.getMap("UR"); Ur ur = ss.get(id); return ur.toString(); } // 查询所有的 keys @GetMapping("/all") public String all(){ RKeys keys = redissonClient.getKeys(); Iterable<String> keys1 = keys.getKeys(); keys1.forEach(System.out::println); return keys.toString(); } // ================== ==============读写锁测试 ============================= @GetMapping("/rw/set/{key}") public void rw_set(){// RedissonLock. RBucket<String> ls_count = redissonClient.getBucket("LS_COUNT"); ls_count.set("300",360000000l, TimeUnit.SECONDS); } // 减法运算 @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("================线程已结束================================" + s); return s; }}
4.3 扩展
4.3.1 丰富的jar支持,尤其是对 Netty NIO框架文章源自JAVA秀-https://www.javaxiu.com/42212.html
4.3.2 丰富的配置机制选择,这里是详细的配置说明文章源自JAVA秀-https://www.javaxiu.com/42212.html
https://github.com/redisson/redisson/wiki/2.-Configuration文章源自JAVA秀-https://www.javaxiu.com/42212.html
关于序列化机制中,就有很多文章源自JAVA秀-https://www.javaxiu.com/42212.html
文章源自JAVA秀-https://www.javaxiu.com/42212.html
SpringBoot 操作 Reis的各种实现(以及Jedis、Redisson、Lettuce的区别比
图片
文章源自JAVA秀-https://www.javaxiu.com/42212.html4.3.3 API支持(部分展示),具体的 Redis --> RedissonClient ,可查看这里文章源自JAVA秀-https://www.javaxiu.com/42212.html
https://github.com/redisson/redisson/wiki/11.-Redis-commands-mapping文章源自JAVA秀-https://www.javaxiu.com/42212.html
文章源自JAVA秀-https://www.javaxiu.com/42212.html
图片文章源自JAVA秀-https://www.javaxiu.com/42212.html
4.3.4 轻便的丰富的锁机制的实现文章源自JAVA秀-https://www.javaxiu.com/42212.html
Lock文章源自JAVA秀-https://www.javaxiu.com/42212.html
Fair Lock文章源自JAVA秀-https://www.javaxiu.com/42212.html
MultiLock文章源自JAVA秀-https://www.javaxiu.com/42212.html
RedLock文章源自JAVA秀-https://www.javaxiu.com/42212.html
ReadWriteLock文章源自JAVA秀-https://www.javaxiu.com/42212.html
Semaphore文章源自JAVA秀-https://www.javaxiu.com/42212.html
PermitExpirableSemaphore文章源自JAVA秀-https://www.javaxiu.com/42212.html
CountDownLatch文章源自JAVA秀-https://www.javaxiu.com/42212.html
四、基于注解实现的Redis缓存
4.1 Maven 和 YML配置
参考 RedisTemplate 配置。文章源自JAVA秀-https://www.javaxiu.com/42212.html
另外,还需要额外的配置类文章源自JAVA秀-https://www.javaxiu.com/42212.html
// todo 定义序列化,解决乱码问题@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); // 解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // 配置序列化(解决乱码的问题) 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 使用示例
@Transactional@Servicepublic 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"; // =====================================================================使用Spring cahce 注解方式实现缓存 // ==================================单个操作 @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 自定义redis缓存的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 这里缓存到redis,还有响应页面是String(加了很多转义符\,),不是Json格式 @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 缓存json,不乱码已处理好,调整序列化和反序列化 @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); } // ==================================删除缓存 @Override @CacheEvict(value = "cache:customer", key = "'cacheOne5' + '.' + #id") public Object del(Integer id) { // 删除缓存后的逻辑 return null; } @Override @CacheEvict(value = "cache:customer",allEntries = true) public void del() { } @CacheEvict(value = "cache:all",allEntries = true) public void delall() { } // ==================List操作 @Override @Cacheable(value = "cache:all") public List<CustomersEntity> cacheList() { List<CustomersEntity> all = customerRepo.findAll(); return all; } // todo 先查询缓存,再校验是否一致,然后更新操作,比较实用,要清楚缓存的数据格式(明确业务和缓存模型数据) @Override @CachePut(value = "cache:all",unless = "null == #result",key = "#root.methodName") public List<CustomersEntity> cacheList2() { List<CustomersEntity> all = customerRepo.findAll(); return all; }}
4.3 扩展
基于spring缓存实现文章源自JAVA秀-https://www.javaxiu.com/42212.html
文章源自JAVA秀-https://www.javaxiu.com/42212.html
图片文章源自JAVA秀-https://www.javaxiu.com/42212.html
欢迎一键三连文章源自JAVA秀-https://www.javaxiu.com/42212.html
1. 你真的会写for循环吗?来看看这些常见的for循环优化方式2. SpringCloud常见面试题(2021最新版)3. 神奇的 SQL 之别样的写法 → 行行比较4. 华为OD(外包)社招技术二面,总结复盘最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。文章源自JAVA秀-https://www.javaxiu.com/42212.html
谢谢支持哟 (*^__^*)文章源自JAVA秀-https://www.javaxiu.com/42212.html

评论