一、Jedis,Redisson,Lettuce 三者的區別
共同點:都提供了基於 Redis 操作的 Java API,只是封裝程度,具體實現稍有不同。
不同點:
-
1.1、Jedis
是 Redis 的 Java 實現的客戶端。支持基本的數據類型如:String、Hash、List、Set、Sorted Set。
特點:使用阻塞的 I/O,方法調用同步,程序流需要等到 socket 處理完 I/O 才能執行,不支持異步操作。Jedis 客戶端實例不是線程安全的,需要通過連接池來使用 Jedis。
-
1.1、Redisson
優點點:分布式鎖,分布式集合,可通過 Redis 支持延遲隊列。
-
1.3、 Lettuce
用於線程安全同步,異步和響應使用,支持集群,Sentinel,管道和編碼器。
基於 Netty 框架的事件驅動的通信層,其方法調用是異步的。Lettuce 的 API 是線程安全的,所以可以操作單個 Lettuce 連接來完成各種操作。
二、Jedis
三、RedisTemplate
3.1、使用配置
maven 配置引入,(要加上版本號,這里是因為 Parent 已聲明)
<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 # 指定redis的分庫(共16個0到15)
3.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; }
3.3、擴展
3.3.1、spring-boot-starter-data-redis 的依賴包

3.3.2、stringRedisTemplate API(部分展示)
opsForHash --> hash 操作
opsForList --> list 操作
opsForSet --> set 操作
opsForValue --> string 操作
opsForZSet --> Zset 操作
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 操作示例
4.1 基本配置
4.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>
4.1.2、添加配置文件 Yaml 或者 json 格式
redisson-config.yml
# 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: false
threads: 0
nettyThreads: 0
codec:
class: "org.redisson.codec.JsonJacksonCodec"
transportMode: "NIO"
或者,配置 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 }
4.1.3、讀取配置
新建讀取配置類
@Configuration public 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 中配置如下
spring:
redis:
redisson:
config: classpath:redisson-config.yaml
4.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 框架
4.3.2 豐富的配置機制選擇,這里是詳細的配置說明
關於序列化機制中,就有很多


4.3.3 API 支持(部分展示),具體的 Redis --> RedissonClient , 可查看這里

4.3.4 輕便的豐富的鎖機制的實現
4.3.4.1 Lock
4.3.4.2 Fair Lock
4.3.4.3 MultiLock
4.3.4.4 RedLock
4.3.4.5 ReadWriteLock
4.3.4.6 Semaphore
4.3.4.7 PermitExpirableSemaphore
4.3.4.8 CountDownLatch
五、基於注解實現的 Redis 緩存
5.1 Maven 和 YML 配置
參考 RedisTemplate 配置
另外,還需要額外的配置類
// 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;
}
}
5.2 使用示例
@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";
// =====================================================================使用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;
}
}
5.3 擴展
基於 spring 緩存實現
