iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >利用redis实现聊天记录转存功能的全过程
  • 704
分享到

利用redis实现聊天记录转存功能的全过程

2024-04-02 19:04:59 704人浏览 薄情痞子
摘要

目录前言环境搭建实现思路实现过程自定义RedisTemplate封装redis工具类进行单元测试测试list数据的写入与获取测试list数据的取出测试聊天记录转移至数据库解析客户端数

前言

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

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

环境搭建

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


<!-- Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 定时任务调度 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
    <version>2.3.7.RELEASE</version>
</dependency>

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


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

实现思路

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

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

  1. 解析客户端数据,构造实体类
  2. 将数据保存至redis
  3. 使用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文件,我们再此文件中配置其默认序列化规则,它的代码如下:


package com.lk.config;

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.GenericJackson2jsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


// 自定义RedisTemplate设置序列化器, 方便转换redis中的数据与实体类互转
@Configuration
public class LettuceRedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        // 使用GenericJackson2JsonRedisSerializer替换默认序列化
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置 Key 和 Value 的序列化规则
        redisTemplate.seTKEySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        // 初始化 RedisTemplate 序列化完成
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

封装redis工具类

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

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


package com.lk.utils;

import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
// Redis操作工具类
public class RedisOperatingUtil {
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;

    
    public void setKeyTime(String key, long time) {
        redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }

    
    public Long getKeyTime(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    
    public Long delkey(String... key) {
        if (key == null || key.length < 1) {
            return 0L;
        }
        return redisTemplate.delete(Arrays.asList(key));
    }

    
    public String keyType(String key) {
        DataType dataType = redisTemplate.type(key);
        assert dataType != null;
        return dataType.code();
    }

    
    public void barchSet(Map<String, Object> map) {
        redisTemplate.opsForValue().multiSet(map);
    }

    
    public List<Object> batchGet(List<String> list) {
        return redisTemplate.opsForValue().multiGet(Collections.singleton(list));
    }


    
    public Object objectGetKey(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    
    public void objectSetValue(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    
    public Long listLeftPush(String key, Object value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    
    public Long listRightPush(String key, Object value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    
    public Long listLeftPushAll(String key, List<Object> value) {
        return redisTemplate.opsForList().leftPushAll(key, value);
    }

    
    public Long listRightPushAll(String key, List<Object> value) {
        return redisTemplate.opsForList().rightPushAll(key, value);
    }

    
    public void listIndexSet(String key, long index, Object value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    
    public Object listRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    
    public Object listPopLeftKey(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    
    public Object listPopRightKey(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    
    public Long listLen(String key) {
        return redisTemplate.opsForList().size(key);
    }

    
    public Object listIndex(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    
    public Long listRem(String key, long count, Object value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }

    
    public void listTrim(String key, long start, long end) {
        redisTemplate.opsForList().trim(key, start, end);
    }
}

进行单元测试

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

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

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

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

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


package com.lk.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
// 聊天记录-消息内容
public class SubMessage {
  private Integer id;
  private String msgText; // 消息内容
  private String createTime; // 创建时间
  private String userName; // 用户名
  private String userId; // 推送方用户id
  private String avatarSrc; // 推送方头像
  private String msgId; // 接收方用户id
  private Boolean status; // 消息状态
}

测试list数据的写入与获取

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


    @Test
    public void testSerializableListRedisTemplate() {
        // 构造聊天记录实体类数据
        SubMessage subMessage = new SubMessage();
        subMessage.setAvatarSrc("https://www.kaisir.cn/uploads/1ece3749801d4d45933ba8b31403c685touxiang.jpeg");
        subMessage.setUserId("1090192");
        subMessage.setUserName("神奇的程序员");
        subMessage.setMsgText("你好");
        subMessage.setMsgId("2901872");
        subMessage.setCreateTime("2020-12-12 18:54:06");
        subMessage.setStatus(false);
        // 将聊天记录对象保存到redis中
        redisOperatingUtil.listRightPush("subMessage", subMessage);
        // 获取list中的数据
        Object resultObj = redisOperatingUtil.listRange("subMessage", 0, redisOperatingUtil.listLen("subMessage"));
        // 将Object安全的转为List
        List<SubMessage> resultList = ObjectToOtherUtil.castList(resultObj, SubMessage.class);
        // 遍历获取到的结果
        if (resultList != null) {
            for (SubMessage message : resultList) {
                System.out.println(message.getUserName());
            }
        }
    }

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


package com.lk.utils;

import java.util.ArrayList;
import java.util.List;

public class ObjectToOtherUtil {
    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }
}

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

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

注意:如果你的项目对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中存储的两条数据。

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

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

我们测试下将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中的数据也被删除。

解析客户端数据保存至redis

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

这里有个坑,因为websocket服务类中用到了@Component,会导致redis的工具类注入失败,出现null的情况,解决这个问题需要将当前类名声明为静态变量,然后在init中获取赋值redis工具类,代码如下:


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

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


    
    @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步:

  1. 创建任务类编写任务内容
  2. 在QuartzConfig文件中设置定时,执行第一步创建的任务。

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


package com.lk.quartzServer;

import com.lk.dao.SubMessageMapper;
import com.lk.entity.SubMessage;
import com.lk.utils.RedisOperatingUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import javax.annotation.Resource;

// 将redis数据放进mysql中
@Slf4j
public class RedisToMysqlTask extends QuartzJobBean {
    @Resource
    private RedisOperatingUtil redisOperatingUtil;
    @Resource
    private SubMessageMapper subMessageMapper;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        // 获取存储在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+ "条聊天记录,已写入数据库");
    }
}

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


package com.lk.config;

import com.lk.quartzServer.RedisToMysqlTask;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail RedisToMysqlQuartz() {
        // 执行定时任务
        return JobBuilder.newJob(RedisToMysqlTask.class).withIdentity("CallPayQuartzTask").storeDurably().build();
    }

    @Bean
    public Trigger CallPayQuartzTaskTrigger() {
        //cron方式,从每月1号开始,每隔三天就执行一次
        return TriggerBuilder.newTrigger().forJob(RedisToMysqlQuartz())
                .withIdentity("CallPayQuartzTask")
                .withSchedule(CronScheduleBuilder.cronSchedule("* * 4 1/3 * ?"))
                .build();
    }
}

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

实现效果

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

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

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

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

总结

到此这篇关于利用redis实现聊天记录转存功能的文章就介绍到这了,更多相关redis聊天记录转存内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 利用redis实现聊天记录转存功能的全过程

本文链接: https://www.lsjlt.com/news/131749.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 利用redis实现聊天记录转存功能的全过程
    目录前言环境搭建实现思路实现过程自定义RedisTemplate封装redis工具类进行单元测试测试list数据的写入与获取测试list数据的取出测试聊天记录转移至数据库解析客户端数...
    99+
    2024-04-02
  • redis中怎么实现聊天记录转存功能
    这篇文章将为大家详细讲解有关redis中怎么实现聊天记录转存功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。环境搭建我的项目是基于SpringBoot2.x搭建的,电脑已经安装了redis...
    99+
    2023-06-20
  • 利用C++实现Window环境聊天室功能
    本篇内容主要讲解“利用C++实现Window环境聊天室功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“利用C++实现Window环境聊天室功能”吧!C++ Window环境聊天室,供大家参考,...
    99+
    2023-06-20
  • vue3+koa实现文件上传功能的全过程记录
    目录前言:技术引用:前端实现后台实现:引入koa-body,并注册中间件:引入koa-static 进行静态资源访问前台回显图片:遇到的问题:已解决:Token验证问题:proxy代...
    99+
    2023-01-04
    vue进行文件上传 vue3 koa文件上传 vue3 koa
  • Android实现页面跳转的全过程记录
    目录1、启动新Activty1.1、功能分析1.2、开发视图布局1.3、按钮事件响应1.4、测试结果2、启动其他App2.1、功能分析2.2、开发视图布局2.3、按钮事件响应2.4、...
    99+
    2024-04-02
  • Vue导出Excel功能的全过程记录
    目录1.前端主导流程: 2. 插件使用及初始化 2.1  借助vue-admin中提供的方法。2.2  安装插件依赖。2.3  回调函数内容如下3.对后...
    99+
    2024-04-02
  • unity使用socket编程实现聊天室功能
    本文实例为大家分享了unity使用socket实现聊天室功能的具体代码,供大家参考,具体内容如下 示例: 什么是Socket: Socket(套接字),用来描述IP地址和端口,是通...
    99+
    2024-04-02
  • 在SpringBoot中利用Websocket实现一个网页聊天功能
    这篇文章将为大家详细讲解有关在SpringBoot中利用Websocket实现一个网页聊天功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。导入websocket的包。通过使用SpringB...
    99+
    2023-05-31
    springboot websocket bs
  • vue粘贴复制功能的实现过程记录
    目录引言1. 项目需求图展示:1. 安装第三方插件方法(不推荐)2. 浏览器自带Document.execCommand()复制方法(不推荐)3. Clipboard.writeTe...
    99+
    2024-04-02
  • 利用Redis如何实现自动补全功能
    忘了redis从哪个版本开启,能够根据输入的部分命令前缀给出提示,即自动补全。接下来笔者介绍基于redis实现这个很酷的功能。 about sorted set 假设结果中有mara,marabel,ma...
    99+
    2024-04-02
  • 如何利用微信小程序和php实现即时通讯聊天功能
    目录一、PHP7安装Swoole扩展1、自定义安装2、宝塔面板安装PHP swoole扩展二、配置nginx反向代理三、微信小程序socket合法域名配置四、效果演示和代码1、小程序...
    99+
    2024-04-02
  • 如何用PHP实现微信小程序的实时聊天功能?
    如何用PHP实现微信小程序的实时聊天功能?随着移动互联网的发展,微信小程序成为了很多开发者的首选平台。而实时聊天功能作为一种关键的社交功能,很多用户都希望在自己的小程序中实现。本文将介绍如何使用PHP来实现微信小程序的实时聊天功能,并提供具...
    99+
    2023-10-27
    PHP 微信小程序 实时聊天
  • 利用Pycharm连接服务器的全过程记录
    前言 当下,很多深度学习的模型需要高配置的设备来跑,本地的pc可能无法满足要求。所以就需要利用服务器来训练,但是在服务器上操作代码不是很方便。利用Pycharm可以在本地编写/修改代...
    99+
    2024-04-02
  • Java利用过滤器实现完善登录功能
    目录1、问题引入2、解决思路3、代码实现3.1 定义登录校验过滤器3.2 开启组件扫描1、问题引入 我们已经完成了后台系统的登录功能开发,但是目前还存在一个问题,就是用户如果不登录,...
    99+
    2024-04-02
  • 如何利用HTML5+css3+jquery+weui实现仿微信聊天界面功能
    这篇文章主要介绍如何利用HTML5+css3+jquery+weui实现仿微信聊天界面功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!最新因项目需要,就利用HTML5+css3+jquery+weui做了一个仿微信...
    99+
    2023-06-09
  • thinkphp中怎么利用redis实现秒杀缓存功能
    thinkphp中怎么利用redis实现秒杀缓存功能,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1,安装redis,根据自己的php版本安装对应的redis扩...
    99+
    2023-06-19
  • 聊聊怎么用php轻松实现WebP转JPG的功能
    近年来,随着Web技术的不断发展,WebP这种新型图片格式逐渐走进了程序员和Web开发者的视野。WebP优点不容忽视:文件体积小、质量高、浏览器支持度高等。但是在某些情况下,我们可能需要把WebP图片转换成一些其他格式的图片,比如JPG。那...
    99+
    2023-05-14
    webp jpg php
  • 如何利用Redis和Go语言实现缓存功能
    如何利用Redis和Go语言实现缓存功能缓存是一种常见的性能优化技术,它通过将数据存储在高速读取的介质中,例如内存中,来提高数据访问速度。Redis是一种高性能的键值存储数据库,Go语言是一种轻量级并发编程语言,两者的结合可以实现高效的缓存...
    99+
    2023-10-22
    Go语言 redis 缓存功能
  • Nginx配置ssl实现https的全过程记录
    目录一、安装Nginxssl模块1.检查2.安装3.再次检查二、部署ssl证书三、配置nginx.conf四、重启Nginx总结一、安装 Nginx ssl 模块 1.检查 检查是否...
    99+
    2024-04-02
  • 怎么用Java Socket+多线程实现多人聊天室功能
    这篇文章主要讲解了“怎么用Java Socket+多线程实现多人聊天室功能”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么用Java Socket+多线程实现多人聊天室功能”吧!思路简介分...
    99+
    2023-06-20
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作