您当前的位置:首页 > 电脑百科 > 数据库 > Redis

还在只用RedisTemplate访问Redis吗

时间:2022-12-24 15:46:46  来源:今日头条  作者:Java热点

开始准备

开始之前我们需要有redis安装,我们采用本机Docker运行Redis, 主要命令如下

docker pull redisdocker run --name my_redis -d -p 6379:6379 redisdocker exec -it my_redis bashredis-cli复制代码

前面两个命令是启动redis docker, 后两个是连接到docker, 在使用redis-cli 去查看redis里面的内容,主要查看我们存在redis里面的数据。

RedisTemplate

我们先从RedisTemplate开始,这个是最好理解的一种方式,我之前在工作中也使用过这种方式,先看代码示例 我们先定义一个POJO类

@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class Book implements Serializable {private Long id;private String name;private String author;复制代码

一个很简单的BOOK类,三个字段: id,name和author. 再来一个RedisTemplate的Bean

@Beanpublic RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);return template;复制代码

再定义一个使用这个RedisTemplate的Service类

public Optional findOneBook(string name) {HashOperations HashOperations = redisTemplate.opsForHash();if (redisTemplate.hasKey(CACHE) && hashOperations.hasKey(CACHE, name)) {log.info("Get book {} from Redis.", name);return Optional.of(hashOperations.get(CACHE, name));Optional book = bookRepository.getBook(name);log.info("Book Found: {}", book);if (book.isPresent()) {log.info("Put book {} to Redis.", name);hashOperations.put(CACHE, name, book.get());redisTemplate.expire(CACHE, 10, TimeUnit.MINUTES);return book;复制代码

我们使用Hash来存储这个Book信息,在上面的方法中查找书名存不存在Redis中,如果存在就直接返回,如果不存在就去持久化存储中找,找到就再通过Template写入到Redis中, 这是缓存的通用做法。 使用起来感觉很方便。 我们这里为了简单没有使用持久化存储,就硬编码了几条数据, 代码如下

@Repositorypublic class BookRepository {Map bookMap = new HashMap<>();public BookRepository(){bookMap.put("Apache kafka", Book.builder().name("apache kafka").id(1L).author("zhangsan").build());bookMap.put("Python/ target=_blank class=infotextkey>Python", Book.builder().name("python").id(2L).author("lisi").build());public Optional getBook(String name){if(bookMap.contAInsKey(name)){return Optional.of(bookMap.get(name));else{return Optional.empty();复制代码

我们调用 bookService.findOneBook("python")和bookService.findOneBook("apache kafka"); 来把数据写入到换存中

我们来看下存储在Redis的数据长什么样子。

127.0.0.1:6379> keys *1) "xacxedx00x05tx00x04book"127.0.0.1:6379> type "xacxedx00x05tx00x04book"hash127.0.0.1:6379> hgetall "xacxedx00x05tx00x04book"1) "xacxedx00x05tx00x06python"2) "xacxedx00x05srx00&com.ken.redistemplatesample.model.Book=x19x96xfbx7fx7fxdaxbex02x00x03Lx00x06authortx00x12LJAVA/lang/String;Lx00x02idtx00x10LJava/lang/Long;Lx00x04nameqx00~x00x01xptx00x04lisisrx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x00x00x00x00x00x02tx00x06python"3) "xacxedx00x05tx00x0capache kafka"4) "xacxedx00x05srx00&com.ken.redistemplatesample.model.Book=x19x96xfbx7fx7fxdaxbex02x00x03Lx00x06authortx00x12Ljava/lang/String;Lx00x02idtx00x10Ljava/lang/Long;Lx00x04nameqx00~x00x01xptx00bzhangsansrx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x00x00x00x00x00x01tx00x0capache kafka"复制代码

我们可以看到数据被存在了key是“xacxedx00x05tx00x04book”的一个Hash表中, Hash里面有两条记录。 大家发现一个问题没有? 就是这个key不是我们想象的用“book”做key,而是多了一串16进制的码, 这是因为RedisTemplate使用了默认的JdkSerializationRedisSerializer 去序列化我们的key和value, 如果大家都用Java语言那没有问题, 如果有人用Java语言写,有人用别的语言读,那就有问题,就像我开始的时候用hgetall "book"始终拿不到数据那样。 RedisTemplate也提供了StringRedisTemplate来方便大家需要使用String来序列化redis里面的数据。简单看下代码


@Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;public Optional getBookString(String name){HashOperations hashOperations = stringRedisTemplate.opsForHash();if (stringRedisTemplate.hasKey(STRINGCACHE) && hashOperations.hasKey(STRINGCACHE, name)) {log.info("Get book {} from Redis.", name);return Optional.of(hashOperations.get(STRINGCACHE, name));Optional book = bookRepository.getBook(name);log.info("Book Found: {}", book);if (book.isPresent()) {log.info("Put book {} to Redis.", name);hashOperations.put(STRINGCACHE, name, book.get().getAuthor());stringRedisTemplate.expire(STRINGCACHE, 10, TimeUnit.MINUTES);return Optional.of(book.get().getAuthor());return Optional.empty();复制代码

使用上就没有那么方便,你就得自己写需要存的是哪个字段,读出来是哪个字段。

127.0.0.1:6379> keys *1) "string_book"127.0.0.1:6379> hgetall string_book1) "python"2) "lisi"3) "apache kafka"4) "zhangsan"复制代码

如上图所示,使用客户端读出来看起来就比较清爽一些。也可以看到占用的Size会小很多,我们这个例子相差7倍,如果是数据量大,这个还是比较大的浪费。

127.0.0.1:6379> keys *1) "xacxedx00x05tx00x04book"2) "string_book"127.0.0.1:6379> memory usage "string_book"(integer) 104127.0.0.1:6379> memory usage "xacxedx00x05tx00x04book"(integer) 712复制代码JPA Repository

我们知道使用JPA Repository来访问DataBase的时候,增删改查那样的操作能够很方便的实现,基本就是定义个接口,代码都不用写,Spring就帮我们完成了大部分的工作,那么访问Redis是不是也可以这样呢? 答案是肯定的,我们来看代码 首先我们还是定义一个POJO

@RedisHash(value = "cache-book", timeToLive = 600)@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class CacheBook implements Serializable {@Idprivate Long userId;@Indexedprivate String name;private String author;复制代码

这个类与我们上面template上面的类的区别就是我们加了两个注解, 在类开头加了 @RedisHash(value = "cache-book", timeToLive = 600) 在字段上面加了@Id和@Indexed 定义一个Repository的接口

public interface CacheBookRepository extends CrudRepository {Optional findOneByName(String name);复制代码

再定义一个service和上面那个例子template一样,缓存中有就到缓存中拿,没有就到持久化存储中找,并写入缓存

@Slf4j@Servicepublic class BookService {private static final String CACHE = "repository-book";@Autowiredprivate CacheBookRepository cacheRepository;@Autowiredprivate BookRepository bookRepository;public Optional findOneBook(String name) {Optional optionalCacheBook = cacheRepository.findOneByName(name);if(!optionalCacheBook.isPresent())Optional book = bookRepository.getBook(name);log.info("Book Found: {}", book);if (book.isPresent()) {log.info("Put book {} to Redis.", name);cacheRepository.save(book.get());return book;return optionalCacheBook;复制代码

代码很简单,简单到不敢相信是真的。 还是一样,调用这个方法,我们来看存在Redis里面的数据

127.0.0.1:6379> keys *1) "repository-book:2"2) "repository-book:2:idx"3) "repository-book"4) "repository-book:name:apache kafka"5) "repository-book:name:python"6) "repository-book:1:idx"7) "repository-book:1"复制代码

哇,感觉存的内容有些多, 不用怕我们来看下各自存什么数据 首先看最短的一个

127.0.0.1:6379> smembers repository-book1) "1"2) "2"复制代码

它里面存的是我们的id所有的value, 可以用来判断id是否存在 再来看

127.0.0.1:6379> hgetall repository-book:21) "_class"2) "com.ken.redisrepositorysample.model.CacheBook"3) "author"4) "lisi"5) "name"6) "python"7) "userId"8) "2"复制代码

这个是我们数据存放的地方

127.0.0.1:6379> smembers repository-book:1:idx1) "repository-book:name:apache kafka"127.0.0.1:6379> smembers "repository-book:name:apache kafka"1) "1"复制代码

另外两个都是set, 存在在它们里面的数据是索引信息。 由此可以看出通过JPA Repository 的方式,代码很少,而且存储的数据也很通用,个人觉得是比较理想的访问方法。

Cache

我们已经看了两种方式,在访问的时候遵循这样的模式:缓存中有就从缓存中返回,没有就从持久化存储中找,然后写入缓存,这部分代码我也不想自己写,那么Cache就是你的救星。 我们先看代码 我们这次使用内存数据库H2作为持久化存储, 放一个schema.sql在resouces下面

drop table t_book if exists;create table t_book (id bigint auto_increment,create_time timestamp,update_time timestamp,name varchar(255),author varchar(200),primary key (id)insert into t_book (name, author, create_time, update_time) values ('python', 'zhangsan', now(), now());insert into t_book (name, author, create_time, update_time) values ('hadoop', 'lisi', now(), now());insert into t_book (name, author, create_time, update_time) values ('java', 'wangwu', now(), now());复制代码

然后定义POJO

@Entity@Table(name = "T_BOOK")@Data@Builder@NoArgsConstructor@AllArgsConstructorpublic class CacheBook implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;private String author;@Column(updatable = false)@CreationTimestampprivate Date createTime;@UpdateTimestampprivate Date updateTime;复制代码

完全是和数据库绑定的代码,和缓存没有任何关系 一个Repository来访问数据库

public interface BookRepository extends JpaRepository {复制代码

定义一个service来调用它

@Slf4j@Service@CacheConfig(cacheNames = "cache-book")public class BookService {@Autowiredprivate BookRepository bookRepository;@Cacheablepublic List findAllCoffee() {return bookRepository.findAll();@CacheEvictpublic void reloadCoffee() {复制代码

这里就比较关键了,在类上加上了注解 @CacheConfig(cacheNames = "cache-book") 在方法上面加上了Cacheable和CacheEvict, Cacheable这个方法就是用来实现逻辑,有就从缓存中拿,没有就从数据库拿的,CacheEvict是调用这个方法的时候清除缓存。 然后再启动入口程序的地方加上注解 @EnableJpaRepositories @EnableCaching(proxyTargetClass = true) 在配置文件Application.properties中加上

spring.jpa.hibernate.ddl-auto=nonespring.jpa.properties.hibernate.show_sql=truespring.jpa.properties.hibernate.format_sql=truemanagement.endpoints.web.exposure.include=*spring.cache.type=redisspring.cache.cache-names=cache-bookspring.cache.redis.time-to-live=600000spring.cache.redis.cache-null-values=falsespring.redis.host=localhost复制代码

这样就可以了, 感觉就是通过配置下就把缓存给完成了,非常的简单 我们来看Redis中是怎么存的

127.0.0.1:6379> keys *1) "cache-book::SimpleKey []"127.0.0.1:6379> get "cache-book::SimpleKey []""xacxedx00x05srx00x13java.util.ArrayListxx81xd2x1dx99xc7ax9dx03x00x01Ix00x04sizexpx00x00x00x03wx04x00x00x00x03srx00(com.ken.rediscachesample.model.CacheBookxecxcbR=xe1Ux9bxf7x02x00x05Lx00x06authortx00x12Ljava/lang/String;Lx00ncreateTimetx00x10Ljava/util/Date;Lx00x02idtx00x10Ljava/lang/Long;Lx00x04nameqx00~x00x03Lx00nupdateTimeqx00~x00x04xptx00bzhangsansrx00x12java.sql.Timestamp&x18xd5xc8x01Sxbfex02x00x01Ix00x05nanosxrx00x0ejava.util.Datehjx81x01KYtx19x03x00x00xpwbx00x00x01x84xff]x85xb0xb-x81x80srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x00x00x00x00x00x01tx00x06pythonsqx00~x00bwbx00x00x01x84xff]x85xb0xb-x81x80sqx00~x00x02tx00x04lisisqx00~x00bwbx00x00x01x84xff]x85xb0xb<xbfxd8sqx00~x00x0bx00x00x00x00x00x00x00x02tx00x06hadoopsqx00~x00bwbx00x00x01x84xff]x85xb0xb<xbfxd8sqx00~x00x02tx00x06wangwusqx00~x00bwbx00x00x01x84xff]x85xb0xb<xbfxd8sqx00~x00x0bx00x00x00x00x00x00x00x03tx00x04javasqx00~x00bwbx00x00x01x84xff]x85xb0xb<xbfxd8x"复制代码

看到没有,就是当成Redis里面的String来存的, 如果数据量比较小,那是非常的方便,如果数据量大,这种方式就有些问题了。

总结

我们看了这三种方式,这里仅仅是做了个入门,每个里面都有很多细节的地方需要去研究和使用,整体的感觉是要想使用的简单,那么存储在Redis中的数据就要量少,量大后,就需要自己来定制了,那基本上要用RedisTemplate来做一些工作。



Tags:Redis   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
16个Redis常见使用场景总结
来源:blog.csdn.net/qq_39938758/article/details/105577370目录 缓存 数据共享分布式 分布式锁 全局ID 计数器 限流 位统计 购物车 用户消息时间线timeline 消息...【详细内容】
2024-04-11  Search: Redis  点击:(4)  评论:(0)  加入收藏
Linux获取Redis 性能指标方法
一、监控指标&Oslash; 性能指标:Performance&Oslash; 内存指标: Memory&Oslash; 基本活动指标:Basic activity&Oslash; 持久性指标: Persistence&Oslash; 错误指标:Error二、监...【详细内容】
2024-04-11  Search: Redis  点击:(5)  评论:(0)  加入收藏
Redis与缓存一致性问题
缓存一致性问题是在使用缓存系统,如Redis时经常遇到的问题。当数据在原始数据源(如数据库)中发生变化时,如何确保缓存中的数据与数据源保持一致,是开发者需要关注的关键问题。一...【详细内容】
2024-04-11  Search: Redis  点击:(3)  评论:(0)  加入收藏
Redis 不再 “开源”,未来采用 SSPLv1 和 RSALv2 许可证
Redis 官方于21日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause...【详细内容】
2024-03-27  Search: Redis  点击:(14)  评论:(0)  加入收藏
Redis“叛逃”开源,得罪了几乎所有人
内存数据库供应商Redis近日在开源界砸下了一块“巨石”。Redis即将转向双许可模式,并实施更为严格的许可条款。官方对此次变更的公告直截了当:从Redis 7.4版本开始,Redis将在Re...【详细内容】
2024-03-25  Search: Redis  点击:(10)  评论:(0)  加入收藏
如何使用 Redis 实现消息队列
Redis不仅是一个强大的内存数据存储系统,它还可以用作一个高效的消息队列。消息队列是应用程序间或应用程序内部进行异步通信的一种方式,它允许数据生产者将消息放入队列中,然...【详细内容】
2024-03-22  Search: Redis  点击:(18)  评论:(0)  加入收藏
Redis不再 “开源”
Redis 官方今日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause 开...【详细内容】
2024-03-21  Search: Redis  点击:(11)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  Search: Redis  点击:(49)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  Search: Redis  点击:(40)  评论:(0)  加入收藏
工作中Redis有哪些好用的运维工具
工作中使用 Redis 时,如果大家公司没有专业运维,可能开发人员就会面临这些运维的工作,包括 Redis 的运行状态监控,数据迁移,主从集群、切片集群的部署和运维等等。本文我就从这三...【详细内容】
2024-02-06  Search: Redis  点击:(56)  评论:(0)  加入收藏
▌简易百科推荐
16个Redis常见使用场景总结
来源:blog.csdn.net/qq_39938758/article/details/105577370目录 缓存 数据共享分布式 分布式锁 全局ID 计数器 限流 位统计 购物车 用户消息时间线timeline 消息...【详细内容】
2024-04-11    书圈  Tags:Redis   点击:(4)  评论:(0)  加入收藏
Linux获取Redis 性能指标方法
一、监控指标&Oslash; 性能指标:Performance&Oslash; 内存指标: Memory&Oslash; 基本活动指标:Basic activity&Oslash; 持久性指标: Persistence&Oslash; 错误指标:Error二、监...【详细内容】
2024-04-11  上海天正信息科技有限    Tags:Redis   点击:(5)  评论:(0)  加入收藏
Redis与缓存一致性问题
缓存一致性问题是在使用缓存系统,如Redis时经常遇到的问题。当数据在原始数据源(如数据库)中发生变化时,如何确保缓存中的数据与数据源保持一致,是开发者需要关注的关键问题。一...【详细内容】
2024-04-11  后端Q    Tags:Redis   点击:(3)  评论:(0)  加入收藏
Redis 不再 “开源”,未来采用 SSPLv1 和 RSALv2 许可证
Redis 官方于21日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause...【详细内容】
2024-03-27  dbaplus社群    Tags:Redis   点击:(14)  评论:(0)  加入收藏
Redis“叛逃”开源,得罪了几乎所有人
内存数据库供应商Redis近日在开源界砸下了一块“巨石”。Redis即将转向双许可模式,并实施更为严格的许可条款。官方对此次变更的公告直截了当:从Redis 7.4版本开始,Redis将在Re...【详细内容】
2024-03-25    51CTO  Tags:Redis   点击:(10)  评论:(0)  加入收藏
如何使用 Redis 实现消息队列
Redis不仅是一个强大的内存数据存储系统,它还可以用作一个高效的消息队列。消息队列是应用程序间或应用程序内部进行异步通信的一种方式,它允许数据生产者将消息放入队列中,然...【详细内容】
2024-03-22  后端Q  微信公众号  Tags:Redis   点击:(18)  评论:(0)  加入收藏
Redis不再 “开源”
Redis 官方今日宣布修改开源协议 &mdash;&mdash; 未来所有版本都将使用 “源代码可用” 的许可证 (source-available licenses)。具体来说,Redis 将不再遵循 BSD 3-Clause 开...【详细内容】
2024-03-21  OSC开源社区    Tags:Redis   点击:(11)  评论:(0)  加入收藏
在Redis中如何实现分布式锁的防死锁机制?
在Redis中实现分布式锁是一个常见的需求,可以通过使用Redlock算法来防止死锁。Redlock算法是一种基于多个独立Redis实例的分布式锁实现方案,它通过协调多个Redis实例之间的锁...【详细内容】
2024-02-20  编程技术汇    Tags:Redis   点击:(49)  评论:(0)  加入收藏
手动撸一个 Redis 分布式锁
大家好呀,我是楼仔。今天第一天开工,收拾心情,又要开始好好学习,好好工作了。对于使用 Java 的小伙伴,其实我们完全不用手动撸一个分布式锁,直接使用 Redisson 就行。但是因为这些...【详细内容】
2024-02-19  楼仔  微信公众号  Tags:Redis   点击:(40)  评论:(0)  加入收藏
工作中Redis有哪些好用的运维工具
工作中使用 Redis 时,如果大家公司没有专业运维,可能开发人员就会面临这些运维的工作,包括 Redis 的运行状态监控,数据迁移,主从集群、切片集群的部署和运维等等。本文我就从这三...【详细内容】
2024-02-06  waynaqua    Tags:Redis   点击:(56)  评论:(0)  加入收藏
站内最新
站内热门
站内头条