使用Redis实现聊天记录转存

网友投稿 1708 2023-05-23

使用Redis实现聊天记录转存

使用Redis实现聊天记录转存

前言

这几天在实现我开源项目的单聊功能,在实现过程中遇到了需要将聊天记录保存至数据库的问题,在收到消息时肯定不能直接存数据库,因为这样在高并发的场景下,数据库就炸了。

于是,我就想到了redis这个东西,第一次听说它是在2年前,但是一直没时间玩他,现在终于遇到了需要使用它的场景,在用的时候学它,本文就跟大家分享下我的实现思路以及过程,欢迎各位感兴趣的开发者阅读本文。

环境搭建

我的项目是基于SpringBoot2.x搭建的,电脑已经安装了redis,用的maven作为jar包管理工具,所以只需要在maven中添加需要的依赖包即可,如果你用的是其他管理工具,请自行查阅如何添加依赖。

本文需要用到依赖:Redis 、quartz,在pom.xml文件的dependencies标签下添加下述代码。

      org.springframework.boot     spring-boot-starter-data-redis        org.springframework.boot     spring-boot-starter-quartz     2.3.7.RELEASE 

在application.yml文件中配置相关参数。

spring: # redis配置   redis:     host: 127.0.0.1 # redis地址     port: 6379 # 端口号     password:  # 密码     timeout: 3000 # 连接超时时间,单位毫秒

实现思路

在websocket的服务中,收到客户端推送的消息后,我们对数据进行解析,构造聊天记录实体类,将其保存至redis中,最后我们使用quartz设置定时任务将redis的数据定时写入mysql中。

我们将上述思路进行下整理:

解析客户端数据,构造实体类将数据保存至redis使用quartz将redis中的数据定时写入mysql

实现过程

实现思路很简单,难在如何将实体类数据保存至redis,我们需要把redis这一块配置好后,才能继续实现我们的业务需求。

redis支持的数据结构类型有:

set 集合,string类型的无序集合,元素不允许重复hash 哈希表,键值对的集合,用于存储对象list 列表,链表结构zset有序集合string 字符串,最基本的数据类型,可以包含任何数据,比如一个序列化的对象,它的字符串大小上限是512MB

redis的客户端分为jedis 和 lettuce,在SpringBoot2.x中默认客户端是使用lettuce实现的,因此我们不用做过多配置,在使用的时候通过RedisTemplate.xxx来对redis进行操作即可。

自定义RedisTemplate

在RedisTemplate中,默认是使用Java字符串序列化,将字符串存入redis后可读性很差,因此,我们需要对他进行自定义,使用Jackson 序列化,以 JSON 方式进行存储。

我们在项目的config包下,创建一个名为LettuceRedisConfig的Java文件,我们再此文件中配置其默认序列化规则,它的代码如下:

封装redis工具类

做完上述操作后,通过RedisTemplate存储到redis中的数据就是json形式的了,接下来我们对其常用的操作封装成工具类,方便我们在项目中使用。

在Utils包中创建一个名为RedisOperatingUtil,其代码如下:

进行单元测试

做完上述操作后,最难弄的一关我们就已经搞定了,接下来我们来对一会需要使用的方法进行单元测试,确保其能够正常运行。

创建一个名为RedisTest的Java文件,注入需要用到的相关类。

redisOperatingUtil为我们的redis工具类subMessageMapper为聊天记录表的dao层

@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class RedisTest {     @Resource     private RedisOperatingUtil redisOperatingUtil;     @Resource     private SubMessageMapper subMessageMapper; }

接下来,我们看下SubMessage实体类的代码。

测试list数据的写入与获取

在单元测试类内部加入下述代码:

在上述代码中,我们从redis中取出的数据是Object类型的,我们要将它转换为与之对应的实体类,一开始我是用的类型强转,但是idea会报黄色警告,于是就写了一个工具类用于将Object对象安全的转换为与之对应的类型,代码如下:

执行后,我们看看redis是否有保存到我们写入的数据,如下所示,已经成功保存。

image-20201213163924700

我们再来看看,代码的执行结果,看看有没有成功获取到数据,如下图所示,也成功取到了。

image-20201213164038308

注意:如果你的项目对websocket进行了启动配置,可能会导致单元测试失败,报错java.lang.IllegalStateException: Failed to load ApplicationContext,解决方案就是注释掉websocket配置文件中的@Configuration即可。

测试list数据的取出

当我们把redis中存储的数据迁移到mysql后,需要删除redis中的数据,一开始我用的是它的delete方法,但是他的delete方法只能删除与之匹配的值,不能选择一个区间进行删除,于是就决定用它的pop方法进行出栈操作。

我们来测试下工具类中的listPopLeftKey方法。

@Test     public void testListPop() {         long item = 0;         // 获取存储在redis中聊天记录的条数         long messageListSize = redisOperatingUtil.listLen("subMessage");         for (int i = 0; i < messageListSize; i++) {             // 从头向尾取出链表中的元素             SubMessage messageResult = (SubMessage) redisOperatingUtil.listPopLeftKey("subMessage");             log.info(messageResult.getMsgText());             item++;         }         log.info(item+"条数据已成功取出");     }

执行结果如下所示,成功取出了redis中存储的两条数据。

image-20201213170726492

测试聊天记录转移至数据库

接下来我们在redis中放入三条数据用于测试

image-20201213171623890

我们测试下将redis中的数据取出,然后写入数据库,代码如下:

// 测试聊天记录转移数据库     @Test     public void testRedisToMysqlTask() {         // 获取存储在redis中聊天记录的条数         long messageListSize = redisOperatingUtil.listLen("subMessage");         // 写入数据库的数据总条数         long resultCount = 0;         for (int i = 0; i < messageListSize; i++) {             // 从头到尾取出链表中的元素             SubMessage subMessage= (SubMessage) redisOperatingUtil.listPopLeftKey("subMessage");             // 向数据库写入数据             int result = subMessageMapper.addMessageTextInfo(subMessage);             if (result > 0) {                 // 写入成功                 resultCount++;             }         }         log.info(resultCount+ "条聊天记录,已写入数据库");     }

执行结果如下,数据已成功写入数据库且redis中的数据也被删除。

image-20201213171834299

image-20201213171956311

image-20201213172031222

解析客户端数据保存至redis

完成上述操作后,我们redis那一块的东西就搞定了,接下来就可以实现将客户端的数据存到redis里了。

// 解决redis操作工具类注入为null的问题     public static WebSocketServer webSocketServer;     @PostConstruct     public void init() {         webSocketServer = this;         webSocketServer.redisOperatingUtil = this.redisOperatingUtil;     }

在websocket服务的@OnMessage注解中,收到客户端发送的消息,我们将其保存到redis中,代码如下:

/**      * 收到客户端消息后调用的方法      *      * @param message 客户端发送过来的消息      *                // @param session 客户端会话      */     @OnMessage     public void onMessage(String message) {         // 客户端发送的消息         JSONObject jsReply = new JSONObject(message);         // 添加在线人数         jsReply.put("onlineUsers", getOnlineCount());         if (jsReply.has("buddyId")) {             // 获取推送方id             String userId = jsReply.getString("userID");             // 获取被推送方id             String buddyId = jsReply.getString("buddyId");             // 非测试数据则推送消息             if (!buddyId.equals("121710f399b84322bdecc238199d6888")) {                 // 发送消息至推送方                 this.sendInfo(jsReply.toString(), userId);             }             // 构造聊天记录实体类数据             SubMessage subMessage = new SubMessage();             subMessage.setAvatarSrc(jsReply.getString("avatarSrc"));             subMessage.setUserId(jsReply.getString("userID"));             subMessage.setUserName(jsReply.getString("username"));             subMessage.setMsgText(jsReply.getString("msg"));             subMessage.setMsgId(jsReply.getString("msgId"));             subMessage.setCreateTime(DateUtil.getThisTime());             subMessage.setStatus(false);             // 将聊天记录对象保存到redis中             webSocketServer.redisOperatingUtil.listRightPush("subMessage", subMessage);             // 发送消息至被推送方             this.sendInfo(jsReply.toString(), buddyId);         }     }

做完上述操作后,收到客户端发送的消息就会自动写入redis。

定时将redis的数据写入mysql

接下来,我们使用quartz定时向mysql中写入数据,他执行定时任务的步骤分为2步:

创建任务类编写任务内容

在QuartzConfig文件中设置定时,执行第一步创建的任务。

首先,创建quartzServer包,在其下创建RedisToMysqlTask.java文件,在此文件内实现redis写入mysql的代码

在config包下创建QuartzConfig.java文件,创建定时任务

这里我设置的定时任务是从每月1号开始,每隔三天就执行一次,Quartz定时任务采用的是cron表达式,自己算这个比较麻烦,这里推荐一个在线网站,可以很容易的生成表达式:Cron表达式生成器

实现效果

最后,配合Vue实现的浏览器端,跟大家展示下实现效果:

效果视频:使用Vue实现单聊

项目浏览器端代码地址:github/chat-system

项目在线体验地址:chat-system

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:什么是RDB和AOF? 一文了解Redis持久化!
下一篇:MySQL 加锁机制验证记录
相关文章