1. 数据类型及常用命令
- 字符串(string):普通字符串,Redis中最简单的数据类型
- 哈希(hash):也叫散列,类似于Java中的HashMap结构,类似于对象
- 列表(list):按照插入顺序排序,可以有重复元素,类似于Java中的LinkedList
- 集合(set):无序集合,没有重复元素,类似于Java中的HashSet
- 有序集合( zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素
SET key value 设置指定key的值 GET key 获取指定key的值 SETEX key seconds value 设置指定key的值,并将 key 的过期时间设为 seconds 秒 SETNX key value 只有在 key不存在时设置 key 的值 ========================================================= HSET key field value 将哈希表 key 中的字段 field 的值设为 value HGET key field 获取存储在哈希表中指定字段的值 HDEL key field 删除存储在哈希表中的指定字段 HKEYS key 获取哈希表中所有字段 HVALS key 获取哈希表中所有值 ========================================================= LPUSH key value1 [value2] 将一个或多个值插入到列表头部 LRANGE key start stop 获取列表指定范围内的元素 RPOP key 移除并获取列表最后一个元素 LLEN key 获取列表长度 BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表 直到等待超时或发现可弹出元素为止 ========================================================= SADD key member1 [member2] 向集合添加一个或多个成员 SMEMBERS key 返回集合中的所有成员 SCARD key 获取集合的成员数 SINTER key1 [key2] 返回给定所有集合的交集 SUNION key1 [key2] 返回所有给定集合的并集 SREM key member1 [member2] 移除集合中一个或多个成员 ========================================================= ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员 ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员 ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment ZREM key member [member ...] 移除有序集合中的一个或多个成员 ========================================================= KEYS pattern 查找所有符合给定模式( pattern)的 key EXISTS key 检查给定 key 是否存在 TYPE key 返回 key 所储存的值的类型 DEL key 该命令用于在 key 存在是删除 key
2. Spring Data Redis
2.1. 概述
前面我们讲解了Redis的常用命令,这些命令是我们操作Redis的基础,那么我们在java程序中应该如何操作Redis呢?这就需要使用Redis的Java客户端,就如同我们使用JDBC操作MySQL数据库一样。
Redis 的 Java 客户端很多,常用的几种:
- Jedis
- Lettuce
- Spring Data Redis
Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-boot-starter-data-redis。
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
2.2. 操作步骤
- 导入Spring Data Redis 的maven坐标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.7.3</version> </dependency>
- 配置Redis数据源
spring: redis: host: 192.168.200.128 port: 6379 password: redis database: 0
- 编写配置类,创建RedisTemplate对象
import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration @Slf4j public class RedisConfiguration { //提前步骤 //添加依赖spring-boot-starter-data-redis //配置数据源yml,指定数据库位置,端口,密码 @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { log.info("开始创建redis模板对象"); RedisTemplate redisTemplate = new RedisTemplate<>(); //设置redis的连接工厂对象 redisTemplate.setConnectionFactory(redisConnectionFactory); //设置redis key的序列化器 redisTemplate.setKeySerializer(new StringRedisSerializer()); return redisTemplate; } }
- 通过RedisTemplate对象操作Redis
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.*; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @SpringBootTest public class SpringRedisTest { @Autowired private RedisTemplate<String,String> redisTemplate; /** * redis 通用字符串命令 */ @Test public void testCommon(){ /* KEYS pattern 查找所有符合给定模式( pattern)的 key EXISTS key 检查给定 key 是否存在 TYPE key 返回 key 所储存的值的类型 DEL key 该命令用于在 key 存在是删除 key */ System.out.println(redisTemplate.keys("*")); System.out.println(redisTemplate.hasKey("age")); System.out.println(redisTemplate.type("age")); redisTemplate.rename("Student","Teacher"); redisTemplate.delete("myset1"); } // @Test // public void testOperation(){ // //获取字符串操作对象 // ValueOperations valueOperations = redisTemplate.opsForValue(); // HashOperations hashOperations = redisTemplate.opsForHash(); // ListOperations listOperations = redisTemplate.opsForList(); // SetOperations setOperations = redisTemplate.opsForSet(); // ZSetOperations zSetOperations = redisTemplate.opsForZSet(); // // } /** * redis String字符串命令 */ @Test public void testString() { /* SET key value 设置指定key的值 GET key 获取指定key的值 SETEX key seconds value 设置指定key的值,并将 key 的过期时间设为 seconds 秒 SETNX key value 只有在 key 不存在时设置 key 的值 */ ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set("age", "刚满18岁"); String age = (String) valueOperations.get("age"); System.out.println(age); valueOperations.set("code", "120", 3, TimeUnit.SECONDS); valueOperations.setIfAbsent("lock", 1); valueOperations.setIfAbsent("lock", 2); } /** * redis Hash字符串命令 */ @Test public void testHash() { /* HSET key field value 将哈希表 key 中的字段 field 的值设为 value HGET key field 获取存储在哈希表中指定字段的值 HDEL key field 删除存储在哈希表中的指定字段 HKEYS key 获取哈希表中所有字段 HVALS key 获取哈希表中所有值 */ HashOperations hashOperations = redisTemplate.opsForHash(); hashOperations.put("Student", "name", "xiaoming"); hashOperations.put("Student","age","18"); System.out.println(hashOperations.get("Student", "name")); System.out.println(hashOperations.get("Student", "age")); Set keys = hashOperations.keys("Student"); List values = hashOperations.values("Student"); System.out.println("keys = " + keys); System.out.println("values = " + values); hashOperations.delete("Student","age"); } /** * redis List字符串命令 */ @Test public void testList(){ /* LPUSH key value1 [value2] 将一个或多个值插入到列表头部 LRANGE key start stop 获取列表指定范围内的元素 RPOP key 移除并获取列表最后一个元素 LLEN key 获取列表长度 */ ListOperations listOperations = redisTemplate.opsForList(); listOperations.leftPushAll("list","a","b","c"); listOperations.leftPush("list","e"); System.out.println(listOperations.range("list", 0, -1)); listOperations.leftPop("list"); listOperations.rightPop("list"); Long size = listOperations.size("list"); System.out.println("size = " + size); } /** * redis Set字符串命令 */ @Test public void testSet(){ /* SADD key member1 [member2] 向集合添加一个或多个成员 SMEMBERS key 返回集合中的所有成员 SCARD key 获取集合的成员数 SINTER key1 [key2] 返回给定所有集合的交集 SUNION key1 [key2] 返回所有给定集合的并集 SREM key member1 [member2] 删除集合中一个或多个成员 */ SetOperations setOperations = redisTemplate.opsForSet(); setOperations.add("myset1","x","y","z"); setOperations.add("myset2","a","b","y"); Set myset1 = setOperations.members("myset1"); System.out.println("myset1 = " + myset1); Long size = setOperations.size("myset1"); System.out.println("size = " + size); System.out.println(setOperations.intersect("myset1", "myset2")); System.out.println(setOperations.union("myset1", "myset2")); setOperations.remove("myset1","x"); } /** * redis ZSet字符串命令 */ @Test public void testZSet(){ /* ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员 ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员 ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment ZREM key member [member ...] 移除有序集合中的一个或多个成员 */ ZSetOperations zSetOperations = redisTemplate.opsForZSet(); zSetOperations.add("zset1","a",10); zSetOperations.add("zset1","b",15); zSetOperations.add("zset1","c",11); zSetOperations.add("zset1","d",11); Set zset1 = zSetOperations.range("zset1", 0, -1); System.out.println("zset1 = " + zset1); zSetOperations.incrementScore("zset1","a",15); zSetOperations.remove("zset1","b"); } }
3. Spring Cache
3.1. 概述
在 Spring 3.1 中引入了多 Cache 的支持,在 spring-context 包中定义了org.springframework.cache.Cache 和 org.springframework.cache.CacheManager 两个接口来统一不同的缓存技术。Cache 接口包含缓存的常用操作:增加、删除、读取等。CacheManager 是 Spring 各种缓存的抽象接口。 Spring 支持的常用 CacheManager 如下:
CacheManager |
描述 |
SimpleCacheManager |
使用简单的 Collection 来存储缓存 |
ConcurrentMapCacheManager |
使用 java.util.ConcurrentHashMap 来实现缓存 |
NoOpCacheManager |
仅测试用,不会实际存储缓存 |
EhCacheCacheManger |
使用EhCache作为缓存技术。EhCache 是一个纯 Java 的进程内缓存框架,特点快速、精干,是 Hibernate 中默认的 CacheProvider,也是 Java 领域应用最为广泛的缓存 |
JCacheCacheManager |
支持JCache(JSR-107)标准的实现作为缓存技术 |
CaffeineCacheManager |
使用 Caffeine 作为缓存技术。用于取代 Guava 缓存技术。 |
RedisCacheManager |
使用Redis作为缓存技术 |
HazelcastCacheManager |
使用Hazelcast作为缓存技术 |
CompositeCacheManager |
用于组合 CacheManager,可以从多个 CacheManager 中轮询得到相应的缓存 |
Spring Cache 提供了 @Cacheable 、@CachePut 、@CacheEvict 、@Caching 等注解,在方法上使用。通过注解 Cache 可以实现类似事务一样、缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码。 核心思想:当我们调用一个方法时会把该方法的参数和返回结果最为一个键值对存放在缓存中,等下次利用同样的参数来调用该方法时将不会再执行,而是直接从缓存中获取结果进行返回。
注解 |
说明 |
@EnableCaching |
开启缓存注解功能,通常加在启动类上 |
@Cacheable |
在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据; 如果没有缓存数据,调用方法并将方法返回值放到缓存中 |
@CachePut |
将方法的返回值放到缓存中 |
@CacheEvict |
将一条或多条数据从缓存中删除 |
@Caching |
缓存的结合体,可以组合以上注解在一个方法中使用,比如有新增,有删除 |
3.2. 操作步骤
- 依赖导入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
- 配置
spring: redis: host: 127.0.0.1 port: 6379 password: 123456 database: 1
- 对应代码
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserService { @Autowired private UserMapper userMapper; /** * 将方法返回值放入缓存 * @param user * @return */ @CachePut(value = "userCache",key = "#user.id") public User insert(User user){ userMapper.insert(user); return user; } /** * * @param id * @return */ @Cacheable(cacheNames = "userCache",key = "#id") public User getById(Long id){ //1.查询redis // String userStr = redisTemplate.opsForValue().get("redis:" + id); // if (userStr!=null){ // //命中 // User user = JSONObject.parseObject(userStr, User.class); // return user; // } //未命中 User user = userMapper.getById(id); if(user == null){ throw new RuntimeException("用户不存在"); } //同步数据到redis中 //redisTemplate.opsForValue().set("redis:" + id, JSON.toJSONString(user)); return user; } /** * 删除某个key对应的缓存数据 * @param id */ @CacheEvict(cacheNames = "userCache",key = "#id") public void deleteById(Long id){ userMapper.deleteById(id); } /** * 删除所有数据,清理所有缓存 */ @CacheEvict(cacheNames = "userCache",allEntries = true) public void deleteAll(){ userMapper.deleteAll(); } /** * hashcode的特点是,只要参数相同,则生成后的hashcode值肯定相同 * 如果返回结果为空,则不缓存unless="#result == null"或unless="#result.size()==0" * unless ="#result.size()==0" result是一个关键字, * @param userDto * @return */ @Cacheable(value = "userCache",key = "#userDto.hashCode()",unless = "#result.size() == 0") public List<User> getList(UserDto userDto){ List<User> list = userMapper.getList("%" + userDto.getName() + "%", userDto.getAge()); return list; } }