redis是最常用的kv数据库,spring 通过模板方式(redistemplate)提供了对redis的数据查询和操作功能。
本文主要介绍基于redistemplate + lettuce方式对redis进行查询和操作的案例。
一、redis基础数据类型
首先对redis来说,所有的key(键)都是字符串。我们在谈基础数据结构时,讨论的是存储值的数据类型,主要包括常见的5种数据类型,分别是:string、list、set、zset、hash。
结构类型 | 结构存储的值 | 结构的读写能力 |
string字符串 | 可以是字符串、整数或浮点数 | 对整个字符串或字符串的一部分进行操作;对整数或浮点数进行自增或自减操作; |
list列表 | 一个链表,链表上的每个节点都包含一个字符串 | 对链表的两端进行push和pop操作,读取单个或多个元素;根据值查找或删除元素; |
set集合 | 包含字符串的无序集合 | 字符串的集合,包含基础的方法有看是否存在添加、获取、删除;还包含计算交集、并集、差集等 |
hash散列 | 包含键值对的无序散列表 | 包含方法有添加、获取、删除单个元素 |
zset有序集合 | 和散列一样,用于存储键值对 | 字符串成员与浮点数分数之间的有序映射;元素的排列顺序由分数的大小决定;包含方法有添加、获取、删除单个元素以及根据分值范围或成员来获取元素 |
二、redis常用连接池
jedis:是redis的java实现客户端,提供了比较全面的redis命令的支持。redisson:实现了分布式和可扩展的java数据结构。lettuce:高级redis客户端,用于线程安全同步,异步和响应使用,支持集群,sentinel,管道和编码器。
三、springboot集成redis案例
1、yml配置常量:
redis:
# 地址
host: 192.168.1.66
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码(如没有密码请注释掉)
password: 123456
# 连接超时时间
timeout: 3000
# 是否开启ssl
ssl: false
lettuce:
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接2、pom.xml引入依赖:
<!--redis依赖-->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-redis</artifactid>
<version>2.4.0</version>
</dependency>
<!--连接池依赖-->
<dependency>
<groupid>org.apache.commons</groupid>
<artifactid>commons-pool2</artifactid>
<version>2.8.0</version>
</dependency>3、redisconfig配置类:
package com.cn.common.conf;
import com.alibaba.fastjson.parser.parserconfig;
import com.alibaba.fastjson.support.config.fastjsonconfig;
import com.alibaba.fastjson.support.spring.fastjsonredisserializer;
import org.apache.commons.pool2.impl.genericobjectpoolconfig;
import org.springframework.beans.factory.annotation.value;
import org.springframework.cache.annotation.enablecaching;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.data.redis.connection.redisstandaloneconfiguration;
import org.springframework.data.redis.connection.lettuce.lettuceconnectionfactory;
import org.springframework.data.redis.connection.lettuce.lettucepoolingclientconfiguration;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.data.redis.serializer.redisserializer;
import org.springframework.data.redis.serializer.stringredisserializer;
import java.nio.charset.standardcharsets;
import java.time.duration;
/**
* redis配置类
*
* @author zq
*/
@configuration
@enablecaching
public class redisconfig {
// 倘若 spring.redis.host 不存在,则会默认为127.0.0.1.
@value("${spring.redis.host:#{'127.0.0.1'}}")
private string hostname;
@value("${spring.redis.port:#{6379}}")
private int port;
@value("${spring.redis.password:#{123456}}")
private string password;
@value("${spring.redis.timeout:#{3000}}")
private int timeout;
@value("${spring.redis.lettuce.pool.max-idle:#{16}}")
private int maxidle;
@value("${spring.redis.lettuce.pool.min-idle:#{1}}")
private int minidle;
@value("${spring.redis.lettuce.pool.max-wait:#{16}}")
private long maxwaitmillis;
@value("${spring.redis.lettuce.pool.max-active:#{16}}")
private int maxactive;
@value("${spring.redis.database:#{0}}")
private int databaseid;
@bean
public lettuceconnectionfactory lettuceconnectionfactory() {
redisconfiguration redisconfiguration = new redisstandaloneconfiguration(
hostname, port
);
// 设置选用的数据库号码
((redisstandaloneconfiguration) redisconfiguration).setdatabase(databaseid);
// 设置 redis 数据库密码
((redisstandaloneconfiguration) redisconfiguration).setpassword(password);
// 连接池配置
genericobjectpoolconfig<object> poolconfig = new genericobjectpoolconfig<>();
poolconfig.setmaxidle(maxidle);
poolconfig.setminidle(minidle);
poolconfig.setmaxtotal(maxactive);
poolconfig.setmaxwaitmillis(maxwaitmillis);
lettucepoolingclientconfiguration.lettucepoolingclientconfigurationbuilder builder
= lettucepoolingclientconfiguration.builder()
.commandtimeout(duration.ofmillis(timeout));
lettucepoolingclientconfiguration lettucepoolingclientconfiguration = builder.build();
builder.poolconfig(poolconfig);
// 根据配置和客户端配置创建连接
lettuceconnectionfactory factory = new lettuceconnectionfactory(redisconfiguration, lettucepoolingclientconfiguration);
return factory;
}
/**
* springboot2.x 使用lettuceconnectionfactory 代替 redisconnectionfactory
* application.yml配置基本信息后,springboot2.x redisautoconfiguration能够自动装配
* lettuceconnectionfactory 和 redisconnectionfactory 及其 redistemplate
*
* @param
* @return
*/
@bean(name = "redistemplate")
public redistemplate<string, object> redistemplate(
lettuceconnectionfactory lettuceconnectionfactory
) {
redistemplate<string, object> redistemplate = new redistemplate<>();
redistemplate.setconnectionfactory(lettuceconnectionfactory);
// 使用 fastjsonredisserializer 来序列化和反序列化redis 的 value的值
fastjsonredisserializer<object> serializer = new fastjsonredisserializer<>(object.class);
parserconfig.getglobalinstance().addaccept("com.muzz");
fastjsonconfig fastjsonconfig = new fastjsonconfig();
fastjsonconfig.setcharset(standardcharsets.utf_8);
serializer.setfastjsonconfig(fastjsonconfig);
// key 的 string 序列化采用 stringredisserializer
stringredisserializer stringredisserializer = new stringredisserializer();
redistemplate.setkeyserializer(stringredisserializer);
redistemplate.sethashkeyserializer(stringredisserializer);
// value 的值序列化采用 fastjsonredisserializer
redistemplate.setvalueserializer(serializer);
redistemplate.sethashvalueserializer(serializer);
redistemplate.afterpropertiesset();
system.out.println(redistemplate.getdefaultserializer());
return redistemplate;
}
@bean
public redisserializer<object> springsessiondefaultredisserializer() {
// 使用 fastjsonredisserializer 来序列化和反序列化redis 的 value的值
fastjsonredisserializer<object> serializer = new fastjsonredisserializer<>(object.class);
parserconfig.getglobalinstance().addaccept("com.muzz");
fastjsonconfig fastjsonconfig = new fastjsonconfig();
fastjsonconfig.setcharset(standardcharsets.utf_8);
serializer.setfastjsonconfig(fastjsonconfig);
return serializer;
}
}
4、redisutil工具类:
package com.cn.util;
import lombok.requiredargsconstructor;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.data.redis.core.stringredistemplate;
import org.springframework.data.redis.serializer.redisserializer;
import org.springframework.data.redis.serializer.stringredisserializer;
import org.springframework.stereotype.component;
import org.springframework.util.collectionutils;
import java.util.list;
import java.util.map;
import java.util.set;
import java.util.concurrent.timeunit;
/**
* @ description: 基于spring和redis的redistemplate工具类
* 针对所有的hash 都是以h开头的方法
* 针对所有的set 都是以s开头的方法 不含通用方法
* 针对所有的list 都是以l开头的方法
* @ modified by:
*/
@component
@requiredargsconstructor
public class redisutils {
private redistemplate redistemplate;
private final stringredistemplate stringredistemplate;
@autowired(required = false)
public void setredistemplate(redistemplate redistemplate) {
redisserializer stringserializer = new stringredisserializer();
redistemplate.setkeyserializer(stringserializer);
redistemplate.sethashkeyserializer(stringserializer);
this.redistemplate = redistemplate;
}
/**
* 获取key
* @param patten
* @return
*/
public set keys(string patten){
return stringredistemplate.keys(patten);
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
*
*/
public boolean expire(string key, long time) {
try {
if (time > 0) {
redistemplate.expire(key, time, timeunit.seconds);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getexpire(string key) {
return redistemplate.getexpire(key, timeunit.seconds);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean haskey(string key) {
try {
return redistemplate.haskey(key);
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@suppresswarnings("unchecked")
public void del(string... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redistemplate.delete(key[0]);
} else {
redistemplate.delete(collectionutils.arraytolist(key));
}
}
}
//============================string=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public object get(string key) {
return key == null ? null : redistemplate.opsforvalue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(string key, object value) {
try {
redistemplate.opsforvalue().set(key, value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(string key, object value, long time) {
try {
if (time > 0) {
redistemplate.opsforvalue().set(key, value, time, timeunit.seconds);
} else {
set(key, value);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(string key, long delta) {
if (delta < 0) {
throw new runtimeexception("递增因子必须大于0");
}
return redistemplate.opsforvalue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(string key, long delta) {
if (delta < 0) {
throw new runtimeexception("递减因子必须大于0");
}
return redistemplate.opsforvalue().increment(key, -delta);
}
//================================map=================================
/**
* hashget
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public object hget(string key, string item) {
return redistemplate.opsforhash().get(key, item);
}
/**
* 获取hashkey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public map<object, object> hmget(string key) {
return redistemplate.opsforhash().entries(key);
}
/**
* hashset
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(string key, map<string, object> map) {
try {
redistemplate.opsforhash().putall(key, map);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* hashset 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(string key, map<string, object> map, long time) {
try {
redistemplate.opsforhash().putall(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(string key, string item, object value) {
try {
redistemplate.opsforhash().put(key, item, value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(string key, string item, object value, long time) {
try {
redistemplate.opsforhash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(string key, object... item) {
redistemplate.opsforhash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hhaskey(string key, string item) {
return redistemplate.opsforhash().haskey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(string key, string item, double by) {
return redistemplate.opsforhash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(string key, string item, double by) {
return redistemplate.opsforhash().increment(key, item, -by);
}
//============================set=============================
/**
* 根据key获取set中的所有值
*
* @param key 键
* @return
*/
public set<object> sget(string key) {
try {
return redistemplate.opsforset().members(key);
} catch (exception e) {
e.printstacktrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean shaskey(string key, object value) {
try {
return redistemplate.opsforset().ismember(key, value);
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sset(string key, object... values) {
try {
return redistemplate.opsforset().add(key, values);
} catch (exception e) {
e.printstacktrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long ssetandtime(string key, long time, object... values) {
try {
long count = redistemplate.opsforset().add(key, values);
if (time > 0) expire(key, time);
return count;
} catch (exception e) {
e.printstacktrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sgetsetsize(string key) {
try {
return redistemplate.opsforset().size(key);
} catch (exception e) {
e.printstacktrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setremove(string key, object... values) {
try {
long count = redistemplate.opsforset().remove(key, values);
return count;
} catch (exception e) {
e.printstacktrace();
return 0;
}
}
//===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public list<object> lget(string key, long start, long end) {
try {
return redistemplate.opsforlist().range(key, start, end);
} catch (exception e) {
e.printstacktrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lgetlistsize(string key) {
try {
return redistemplate.opsforlist().size(key);
} catch (exception e) {
e.printstacktrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public object lgetindex(string key, long index) {
try {
return redistemplate.opsforlist().index(key, index);
} catch (exception e) {
e.printstacktrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lset(string key, object value) {
try {
redistemplate.opsforlist().rightpush(key, value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lset(string key, object value, long time) {
try {
redistemplate.opsforlist().rightpush(key, value);
if (time > 0) expire(key, time);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lset(string key, list<object> value) {
try {
redistemplate.opsforlist().rightpushall(key, value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lset(string key, list<object> value, long time) {
try {
redistemplate.opsforlist().rightpushall(key, value);
if (time > 0) expire(key, time);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lupdateindex(string key, long index, object value) {
try {
redistemplate.opsforlist().set(key, index, value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 移除n个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lremove(string key, long count, object value) {
try {
long remove = redistemplate.opsforlist().remove(key, count, value);
return remove;
} catch (exception e) {
e.printstacktrace();
return 0;
}
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论