前言
redis(remote dictionary server)是一个开源的内存数据库(in-memory database),也被称为数据结构服务器,它支持存储键值对,并提供多种数据结构的操作。
redis具有高性能、丰富的数据结构和灵活的持久化机制,因此在缓存、会话存储、排行榜、计数器、消息队列等场景中得到广泛的应用。
redis主要有以下特点:
内存数据库:redis的所有数据都存储在内存中,这使得它具有非常高的读写速度。虽然数据存储在内存中,但redis也支持将数据持久化到磁盘上,以确保数据的安全性和可恢复性。键值存储:redis以键值对(key-value)的形式存储数据,其中键是唯一的,而值可以是字符串、列表、哈希表、集合、有序集合等多种数据结构。丰富的数据结构:redis支持多种数据结构的操作,如字符串(string)、列表(list)、哈希表(hash)、集合(set)、有序集合(sorted set)等。这些数据结构可以方便地满足不同应用场景的需求。高性能:redis是一个单线程的服务器,它采用异步i/o和事件驱动的方式,使得它能够在单个线程中处理大量的并发请求,从而获得较高的性能。持久化:redis提供了两种方式的数据持久化:rdb快照和aof日志。rdb快照可以将当前内存中的数据以二进制形式写入磁盘,而aof日志则记录了所有写命令,用于在服务重启后重放这些命令以还原数据。分布式:redis支持通过主从复制(master-slave replication)实现数据的读写分离和高可用性。此外,redis还提供了集群(cluster)模式,可以将数据分布在多个节点上,从而实现数据的横向扩展。支持多种编程语言:redis提供了多种编程语言的客户端库,可以方便地在各种不同的编程语言中使用redis。
spring data redis是spring framework生态系统中的一个模块,用于简化使用redis的开发。它提供了对redis的集成和操作的抽象层,使得在spring应用程序中使用redis变得更加方便和高效。
通过使用spring data redis,开发人员可以更加便捷地操作redis数据库,减少了与redis交互的复杂性和重复性工作。同时,它与spring framework的其他模块和特性无缝集成,提供了更强大的功能和灵活性。
spring data redis主要提供以下功能和特性:
对象映射:spring data redis允许开发人员使用注解或xml配置将java对象与redis数据存储之间进行映射。通过这种方式,可以将复杂的java对象直接存储到redis中,并通过简单的api进行读取和更新。高级查询:spring data redis支持通过注解或方法命名约定进行高级查询,例如按条件查询、排序、分页等操作。这样可以方便地使用查询语言来检索和操作redis中的数据。事务支持:spring data redis提供了对redis事务的支持,可以在一系列redis操作中开启、提交或回滚事务,确保数据的一致性和完整性。pub/sub消息订阅/发布:spring data redis支持redis的pub/sub功能,使应用程序能够通过订阅和发布消息来实现解耦和异步通信。缓存支持:spring data redis与spring缓存抽象集成,使得可以轻松地使用redis作为缓存提供器,提高应用程序的性能和响应速度。连接池管理:spring data redis提供了连接池管理功能,通过连接池可以有效地管理和复用redis连接,减少连接的创建和销毁开销,提高性能和资源利用率。
1、引入pom
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>
<dependency>
<groupid>org.apache.commons</groupid>
<artifactid>commons-pool2</artifactid>
</dependency>
2、配置redistemplate
import com.fasterxml.jackson.annotation.jsonautodetect;
import com.fasterxml.jackson.annotation.propertyaccessor;
import com.fasterxml.jackson.databind.objectmapper;
import org.springframework.cache.cachemanager;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.data.redis.cache.rediscacheconfiguration;
import org.springframework.data.redis.cache.rediscachemanager;
import org.springframework.data.redis.connection.redisconnectionfactory;
import org.springframework.data.redis.core.redistemplate;
import org.springframework.data.redis.serializer.jackson2jsonredisserializer;
import org.springframework.data.redis.serializer.redisserializationcontext;
import org.springframework.data.redis.serializer.stringredisserializer;
import java.time.duration;
import java.util.hashmap;
import java.util.hashset;
import java.util.map;
import java.util.set;
@configuration
public class redistemplateconfig {
@bean("redistemplate")
public redistemplate<string, object> redistemplate(redisconnectionfactory connectionfactory) {
redistemplate<string, object> template = new redistemplate<>();
// 设置连接工厂
template.setconnectionfactory(connectionfactory);
// 设置序列化方式
stringredisserializer stringredisserializer = new stringredisserializer();
// key序列化
template.setkeyserializer(stringredisserializer);
// value序列化
template.setvalueserializer(getjackson2jsonredisserializer());
// hash key序列化
template.sethashkeyserializer(stringredisserializer);
// hash value序列化
template.sethashvalueserializer(getjackson2jsonredisserializer());
template.afterpropertiesset();
return template;
}
/**
* 缓存管理器
*
* @param redisconnectionfactory
* @return
*/
@bean
public cachemanager cachemanager(redisconnectionfactory redisconnectionfactory) {
rediscacheconfiguration defaultcacheconfig = rediscacheconfiguration.defaultcacheconfig();
// 设置缓存管理器管理
defaultcacheconfig = defaultcacheconfig
// 缓存的默认过期时间:
.entryttl(duration.ofseconds(36000))
// 设置 key为string序列化
.serializekeyswith(redisserializationcontext.serializationpair.fromserializer(new stringredisserializer()))
// 设置value为json序列化
.serializevalueswith(redisserializationcontext.serializationpair.fromserializer(getjackson2jsonredisserializer()))
// 不缓存空值
.disablecachingnullvalues();
set<string> cachenames = new hashset<>();
// 对每个缓存空间应用不同的配置
map<string, rediscacheconfiguration> configmap = new hashmap<>();
return rediscachemanager.builder(redisconnectionfactory)
.cachedefaults(defaultcacheconfig)
.initialcachenames(cachenames)
.withinitialcacheconfigurations(configmap)
.build();
}
/**
* 获取jackson2jsonredisserializer序列化对象
*
* @return o
*/
private jackson2jsonredisserializer<object> getjackson2jsonredisserializer() {
/* 明文存取 */
jackson2jsonredisserializer<object> jackson2jsonredisserializer = new jackson2jsonredisserializer<>(object.class);
objectmapper om = new objectmapper();
//指定要序列化的域,field,get和set,以及修饰符范围,any是都有包括private和public
om.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any);
jackson2jsonredisserializer.setobjectmapper(om);
return jackson2jsonredisserializer;
}
}
3、配置yml
3.1、单机配置
spring:
redis:
# redis数据库索引(默认为0)
database: 0
# 连接地址
host: 127.0.0.1
#端口号
port: 6379
##连接超时时间
timeout: 3600ms
#密码
password:
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 1
#关闭超时
shutdown-timeout: 500ms
3.2、集群配置
spring:
redis:
cluster:
nodes:
- 127.0.0.1:7001
- 127.0.0.1:7002
- 127.0.0.1:7003
- 127.0.0.1:7004
- 127.0.0.1:7005
- 127.0.0.1:7006
#连接超时时间
timeout: 3600ms
#密码
password:
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 1
#关闭超时
shutdown-timeout: 500ms
4、集成使用
@restcontroller
public class controller {
@resource
private redistemplate redistemplate;
@requestmapping("redis")
public string redis() {
// 测试redis
string key = "uid";
string value = "测试用户";
// 设置值
redistemplate.boundvalueops(key).set(value);
// 取出值
object obj = redistemplate.opsforvalue().get(key);
system.out.println("取出值为:" + obj);
return "操作成功";
}
}
5、工具类封装及使用
实际开发中,使用redis的场景会比较多,可以将reidstemplate的操作封装为工具类,代码如下:
5.1、工具封装
import org.springframework.data.redis.core.redistemplate;
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;
@component
public class redisutils {
private static redistemplate redistemplate = null;
public redisutils(redistemplate redistemplate) {
redisutils.redistemplate = redistemplate;
}
public static redistemplate getredistemplate() {
return redistemplate;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public static boolean expire(string key, long time, timeunit unit) {
try {
if (time > 0) {
redistemplate.expire(key, time, unit);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public static long getexpire(string key) {
return redistemplate.getexpire(key, timeunit.seconds);
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return timeunit
*/
public static long getexpire(string key, timeunit timeunit) {
return redistemplate.getexpire(key, timeunit);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public static boolean haskey(string key) {
try {
return redistemplate.haskey(key);
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public static void del(string... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redistemplate.delete(key[0]);
} else {
redistemplate.delete(collectionutils.arraytolist(key));
}
}
}
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public static object get(string key) {
return key == null ? null : redistemplate.opsforvalue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public static boolean set(string key, object value) {
try {
redistemplate.boundvalueops(key).set(value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
*
* @param key
* @param value
* @param timeout 过期时间
* @param unit 时间单位, 天:timeunit.days 小时:timeunit.hours 分钟:timeunit.minutes
* 秒:timeunit.seconds 毫秒:timeunit.milliseconds
*/
public static boolean setex(string key, object value, long timeout, timeunit unit) {
try {
set(key, value);
if (timeout > 0) {
expire(key, timeout, unit);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public static boolean hset(string key, string item, object value) {
try {
redistemplate.boundhashops(key).put(item, value);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
public static boolean hset(string key, map<string, string> map) {
try {
redistemplate.boundhashops(key).putall(map);
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
*
* @param key
* @param value
* @param timeout 过期时间
* @param unit 时间单位, 天:timeunit.days 小时:timeunit.hours 分钟:timeunit.minutes
* 秒:timeunit.seconds 毫秒:timeunit.milliseconds
*/
public static boolean hsetex(string key, string item, object value, long timeout, timeunit unit) {
try {
hset(key, item, value);
if (timeout > 0) {
expire(key, timeout, unit);
}
return true;
} catch (exception e) {
e.printstacktrace();
return false;
}
}
/**
* 获取所有给定字段的值
*
* @param key
* @return
*/
public static map<object, object> hgetall(string key) {
return redistemplate.boundhashops(key).entries();
}
/**
* 获取所有哈希表中的字段
*
* @param key
* @return
*/
public static set<object> hkeys(string key) {
return redistemplate.boundhashops(key).keys();
}
/**
* 获取哈希表中字段的数量
*
* @param key
* @return
*/
public static long hsize(string key) {
return redistemplate.boundhashops(key).size();
}
/**
* 获取哈希表中所有值
*
* @param key
* @return
*/
public static list<object> hvalues(string key) {
return redistemplate.boundhashops(key).values();
}
/**
* 向一张hash表中读取数据
*/
public static object hget(string key, string item) {
try {
return redistemplate.boundhashops(key).get(item);
} catch (exception e) {
e.printstacktrace();
return null;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public static void hdel(string key, object... item) {
redistemplate.boundhashops(key).delete(item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public static boolean hhaskey(string key, string item) {
return redistemplate.boundhashops(key).haskey(item);
}
/**
* 递增
*
* @param key 键
* // * @param by 要增加几(大于0)
* @return
*/
public static long incr(string key, long increment) {
if (increment < 0) {
throw new runtimeexception("递增因子必须大于0");
}
return redistemplate.boundvalueops(key).increment(increment);
}
/**
* 为哈希表 key 中的指定字段的整数值加上增量 increment
*
* @param key
* @param field
* @param increment
* @return
*/
public static long hincrby(string key, object field, long increment) {
if (increment < 0) {
throw new runtimeexception("递增因子必须大于0");
}
return redistemplate.boundhashops(key).increment(field, increment);
}
}
5.2、封装使用
通过工具类直接操作redis
@restcontroller
public class controller {
@requestmapping("redis")
public string redis() {
// 测试redis
string key = "uid";
string value = "测试用户";
// 设置值
redisutils.set(key, value);
// 取出值
object obj = redisutils.get(key);
system.out.println("取出值为:" + obj);
return "操作成功";
}
}
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论