—————————<<
以 Redis 命令作为方法名称,学习成本低,简单实用。
但是 Jedis 实例是线程不安全的,多线程环境下需要基于连接池来使用。
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>3.7.0version>
dependency>
import redis.clients.jedis.Jedis;
/**
*
* @author chengjiang
*/
public class DemoJedis {
public static void main(String[] args) {
// 1、建立连接
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 2、设置密码
// jedis.auth("密码");
// 3、选择库
jedis.select(0);
// 存入数据
String result = jedis.set("name", "张三");
System.out.println("result = " + result);
// result = OK
// 获取数据
String name = jedis.get("name");
System.out.println(name);
// 张三
}
}
—————————<<
Lettuce 是基于 Netty 实现的,支持同步、异步和响应式编程方式,并且是线程安全的。
支持 Redis 的哨兵模式、集群模式和管道模式。
它是一种可扩展的、线程安全的 Redis 高级客户端。
从 Spring Boot 2.x 开始, Lettuce 已取代 Jedis 成为SpringBoot 默认的 Redis 客户端。
<dependency>
<groupId>io.lettucegroupId>
<artifactId>lettuce-coreartifactId>
<version>5.1.8.RELEASEversion>
dependency>
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.SetArgs;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
/**
* @author chengjiang
*/
public class DemoLettuce {
public static void main(String[] args) {
// <1> 创建单机连接的连接信息
RedisURI redisUri = RedisURI.builder()
.withHost("localhost")
.withPort(6379)
.withTimeout(Duration.of(10, ChronoUnit.SECONDS))
.build();
// <2> 创建客户端
RedisClient redisClient = RedisClient.create(redisUri);
// <3> 创建线程安全的连接
StatefulRedisConnection<String, String> connection = redisClient.connect();
// <4> 创建同步命令
RedisCommands<String, String> redisCommands = connection.sync();
SetArgs setArgs = SetArgs.Builder.nx().ex(5);
String result = redisCommands.set("name33", "李四", setArgs);
System.out.println("result = " + result);
// result = OK
String result2 = redisCommands.get("name33");
System.out.println("result2 = " + result2);
// result2 = 李四
// <5> 关闭连接
connection.close();
// <6> 关闭客户端
redisClient.shutdown();
}
}
—————————<<
SpringDataRedis 是 Spring中数据操作模块 SpringData 中的一员,它提供了对不同Redis客户端的整合(Lettuce和Jedis)
,提供了 RedisTemplate 统一的API来操作Redis。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* spring redis 工具类
*
* @author chengjiang
*/
@Component
public class RedisService {
@Resource
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 自增缓存
* key在Redis中不存在,redis中会创建这个key,并生成一个值,值为1
* key在Redis中存在,那么就会在当前数值的基础上再加1后保存
*
* @param key 缓存的键值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public Long increment(final String key, final Long timeout, final TimeUnit timeUnit) {
Long increment = increment(key);
expire(key, timeout, timeUnit);
return increment;
}
/**
* 自减缓存
*
* @param key 缓存的键值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public Long decrement(final String key, final Long timeout, final TimeUnit timeUnit) {
Long increment = decrement(key);
expire(key, timeout, timeUnit);
return increment;
}
/**
* 自增缓存
* key在Redis中不存在,redis中会创建这个key,并生成一个值,值为1
* key在Redis中存在,那么就会在当前数值的基础上再加1后保存
*
* @param key 缓存的键值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public Long increment(final String key, long delta, final Long timeout, final TimeUnit timeUnit) {
Long increment = increment(key, delta);
expire(key, timeout, timeUnit);
return increment;
}
/**
* 自增缓存
* key在Redis中不存在,redis中会创建这个key,并生成一个值,值为1
* key在Redis中存在,那么就会在当前数值的基础上再加1后保存
*
* @param key 缓存的键值
*/
public Long increment(final String key) {
return redisTemplate.boundValueOps(key).increment();
}
/**
* 自增缓存
* key在Redis中不存在,redis中会创建这个key,并生成一个值,值为1
* key在Redis中存在,那么就会在当前数值的基础上再加1后保存
*
* @param key 缓存的键值
*/
public Long increment(final String key, long delta) {
return redisTemplate.boundValueOps(key).increment(delta);
}
/**
* 自减缓存
*
* @param key 缓存的键值
*/
public Long decrement(final String key, long delta) {
return redisTemplate.boundValueOps(key).decrement(delta);
}
/**
* 自减缓存
*
* @param key 缓存的键值
*/
public Long decrement(final String key) {
return redisTemplate.boundValueOps(key).decrement();
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 定时设置有效时间
*
* @param key Redis键
* @param date 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expireAt(final String key, final Date date) {
return redisTemplate.expireAt(key, date);
}
/**
* 获取有效时间
*
* @param key Redis键
* @return 有效时间
*/
public long getExpire(final String key) {
return redisTemplate.getExpire(key);
}
/**
* 获取有效时间
*
* @param key Redis键
* @return 有效时间
*/
public long getExpire(final String key, final TimeUnit timeUnit) {
return redisTemplate.getExpire(key, timeUnit);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
/**
* 删除Region
*
* @param region
*/
public long deleteRegion(final String region) {
Set keys = redisTemplate.keys(region + "*");
return redisTemplate.delete(keys);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList) {
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList, final long timeout, final TimeUnit unit) {
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
redisTemplate.expire(key, timeout, unit);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
Iterator<T> it = dataSet.iterator();
while (it.hasNext()) {
setOperation.add(it.next());
}
return setOperation;
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final T... dataSet) {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
setOperation.add(dataSet);
return setOperation;
}
/**
* set中移除指定元素
*
* @param key
* @param dataSet
* @return
*/
public <T> Long removeSet(final String key, final Set<T> dataSet) {
return redisTemplate.opsForSet().remove(key, dataSet);
}
public <T> Long removeSet(final String key, T... dataSet) {
return redisTemplate.opsForSet().remove(key, dataSet);
}
/**
* set 出栈
*
* @param key
* @param
* @return
*/
public <T> T popSet(final String key) {
return (T) redisTemplate.opsForSet().pop(key);
}
/**
* 向key对应的value值中批量添加值,可以是集合、数组、多参数
*
* @param key
* @param
* @return
*/
public <T> T addSet(final String key, final T value) {
return (T) redisTemplate.opsForSet().add(key, value);
}
/**
* 获取key对应的值的长度
*
* @param key
* @return
*/
public Long countBySet(final String key) {
return redisTemplate.opsForSet().size(key);
}
/**
* set 出栈
*
* @param key
* @return
*/
public Long countByList(final String key) {
return redisTemplate.opsForList().size(key);
}
/**
* 检查给定的元素是否在Set变量中
*
* @param key
* @param value
* @return
*/
public Boolean isMember(final String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public <T> Set<T> getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}
}
—————————<<
Redisson 是一个在 Redis 的功能基础上实现的 Java 驻内存数据网格客户端。实现了分布式和可扩展的 Java 数据结构,提供很多分布式相关操作服务,例如分布式锁,分布式集合,可通过 Redis 支持延迟队列。
依赖
<dependency>
<groupId>org.redissongroupId>
<artifactId>redisson-spring-boot-starterartifactId>
dependency>
yml配置
spring:
redis:
host: 127.0.0.1
port: 6379
password:
案例:
import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.Test;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.redisson.codec.SerializationCodec;
import org.redisson.config.Config;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author chengjiang
*/
public class DemoRedisson {
/**
* 通用对象桶,可以用来存放任类型的对象
*/
@Test
public void RedissonBucket() {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作对象桶来存储对象(同步)
RBucket<Object> bucket = redissonClient.getBucket("redisson-bucket");
//设置值为victory,过期时间为3小时
bucket.set("测试一下看看", 30, TimeUnit.HOURS);
Object value = bucket.get();
System.out.println("value----" + value);
// value----测试一下看看
//通过key取value值
Object name = redissonClient.getBucket("name444").get();
System.out.println("name----" + name);
// name----测试一下看看
// 关闭客户端
redissonClient.shutdown();
}
/**
* 二进制流
* 提供了InputStream接口和OutputStream接口的实现
*/
@Test
public void RedissonStream() throws IOException {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作流来存储对象
RBinaryStream stream = redissonClient.getBinaryStream("redisson-stream");
// 写入数据方式一
stream.set("你好,".getBytes());
// 写入数据方式一
OutputStream outputStream = stream.getOutputStream();
outputStream.write("测试一下看看".getBytes());
// 读取数据
InputStream inputStream = stream.getInputStream();
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int length;
while ((length = inputStream.read(bytes)) != -1) {
result.write(bytes, 0, length);
}
System.out.println(result.toString());
// 关闭客户端
redissonClient.shutdown();
}
/**
* Redisson操作list
*/
@Test
public void list() {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作list
RList<String> list = redissonClient.getList("redisson-list");
list.add("victory1");
list.add("victory2");
//取值
List<String> list1 = list.readAll();
System.out.println("list1----" + JSON.toJSONString(list1));
// list1----["victory1","victory2"]
//移除索引0位置元素
list.remove(0);
//取值
List<String> list2 = list.readAll();
System.out.println("list2----" + JSON.toJSONString(list2));
// list2----["victory2"]
// 关闭客户端
redissonClient.shutdown();
}
/**
* set
* Redisson操作set
*/
@Test
public void set() {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作list
RSet<Object> set = redissonClient.getSet("redisson-set");
set.add("victory1");
set.add("victory2");
//通过key取value值
Set<Object> set1 = redissonClient.getSet("redisson-set");
System.out.println("set1 -- " + set1);
// set1 -- [victory2, victory1]
// 关闭客户端
redissonClient.shutdown();
}
/**
* map
* Redisson操作map
* Redisson将Redis中的字符串数据结构封装成了RMap,就是原本redis中的string类型
*/
@Test
public void map() {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作list
RMap<Object, Object> map = redissonClient.getMap("redisson-map");
map.put("name1", "victory1");
map.put("name2", "victory2");
//通过key取value值
Object o = redissonClient.getMap("redisson-map").get("name1");
System.out.println(o);
// 关闭客户端
redissonClient.shutdown();
}
/**
* 队列
* Redisson操作queue
*/
@Test
public void queue() {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作queue
RQueue<String> queue = redissonClient.getQueue("redisson-queue");
//存值
queue.add("victory1");
queue.add("victory2");
//取值
String item = queue.poll();
System.out.println(item);
//
RQueue<Object> queue1 = redissonClient.getQueue("redisson-queue");
System.out.println(queue1);
// 关闭客户端
redissonClient.shutdown();
}
/**
* 阻塞队列
* Redisson操作blockingDeque
*/
@Test
public void blockingDeque() throws InterruptedException {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
//阻塞队列
RBlockingQueue<Object> blockingQueue = redissonClient.getBlockingQueue("redisson-blockingDeque");
//延迟队列
RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
delayedQueue.offer("阻塞消息阻塞消息阻塞消息阻塞消息", 30, TimeUnit.SECONDS);
// 获取消息
RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque("redisson-blockingDeque");
Object msg = blockingDeque.take();
System.out.println("msg = " + msg);
}
/**
* 限流器
* Redisson操作rateLimiter
*/
@Test
public void rateLimiter() throws InterruptedException {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作rateLimiter
RRateLimiter rateLimiter = redissonClient.getRateLimiter("redisson-rateLimiter");
// 创建限流器,最大流速:每1秒钟产生20个令牌
rateLimiter.trySetRate(RateType.OVERALL, 20, 10, RateIntervalUnit.SECONDS);
long l2 = System.currentTimeMillis();
for (int i = 0; i < 22; i++) {
rateLimiter.acquire(1);
long l = System.currentTimeMillis();
System.out.println("----------" + i + " = " + (l - l2));
// ----------18 = 0
// ----------19 = 1
// ----------20 = 10008
l2 = l;
}
// 等待执行完成,不设置等待可能出现还未执行完成客户端就关闭的情况
Thread.sleep(2000);
// 关闭客户端
redissonClient.shutdown();
}
/**
* 可重入锁
* Redisson操作RLock
*/
@Test
public void lock() throws InterruptedException {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作lock
RLock lock = redissonClient.getLock("redisson-lock");
for (int i = 0; i < 5; i++) {
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "---" + System.currentTimeMillis() + "---" + "获取了锁");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
}
// 等待执行完成,不设置等待可能出现还未执行完成客户端就关闭的情况
Thread.sleep(30000);
// 关闭客户端
redissonClient.shutdown();
}
/**
* 发布订阅操作
* Redisson操作RTopic执行发布订阅操作
**/
@Test
public void topicPublisherAndSubscriber() throws InterruptedException {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作topic执行发布操作
RTopic topic1 = redissonClient.getTopic("redisson-topic", new SerializationCodec());
// topic1.publish(new Message(1L, "victory", 18));
topic1.publish("消息消息消息消息消息消息");
// 操作topic执行订阅操作
Thread.sleep(5000);
RedissonClient redissonClient1 = Redisson.create(config);
RTopic topic = redissonClient1.getTopic("redisson-topic", new SerializationCodec());
topic.addListener(String.class, (channel, msg) -> {
System.out.println("Redisson接收到消息" + msg);
});
Thread.sleep(10000);
// 关闭客户端
redissonClient.shutdown();
redissonClient1.shutdown();
}
/**
* Redisson利用Redis实现了Java分布式布隆过滤器(Bloom Filter)
* 作用:在缓存层前添加布隆过滤器,常用于高并发场景下应对缓存穿透问题
* 布隆过滤器是一个非常长的二进制向量和一系列随机哈希函数的组合,可用于检索一个元素是否存在;
*/
@Test
public void bloomFilter() {
// 创建Redisson客户端
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
RedissonClient redissonClient = Redisson.create(config);
// 操作布隆过滤器
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("redisson-bloom-filter");
// 初始化布隆过滤器,初始化预期插入的数据量为200,期望误差率为0.01
bloomFilter.tryInit(200, 0.01);
//插入数据
bloomFilter.add("qwe");
bloomFilter.add("asd");
bloomFilter.add("zxc");
//判断是否包含
boolean victory = bloomFilter.contains("qwe");
boolean forward = bloomFilter.contains("cvb");
System.out.println(victory);
//true
System.out.println(forward);
//false
// 关闭客户端
redissonClient.shutdown();
}
}