利用Redis bitmap 实现签到案例

数据库实现

设计签到功能对应的数据库表

 CREATE TABLE `sign_record` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` bigint NOT NULL COMMENT '用户id',
  `year` year NOT NULL COMMENT '签到年份',
  `month` tinyint NOT NULL COMMENT '签到月份',
  `date` date NOT NULL COMMENT '签到日期',
  `is_backup` bit(1) NOT NULL COMMENT '是否补签',
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='签到记录表';

这张表中的一条记录是一个用户一次的签到记录。假如一个用户1年签到100次,而网站有100万用户,就会产生1亿条记录。随着用户量增多、时间的推移,这张表中的数据只会越来越多,占用的空间也会越来越大。

redis bitmap 实现

一个用户签到的情况无非就两种,要么签了,要么没。 可以用 0 或者1如果我们按月来统计用户签到信息,签到记录为1,未签到则记录为0,就可以用一个长度为31位的二级制数来表示一个用户一个月的签到情况。最终效果如下
image.png

java代码
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.orchids</groupId>
  <artifactId>signinbybitmap</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>signinbybitmap</name>
  <description>signinbybitmap</description>
  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.6.13</spring-boot.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>knife4j-spring-boot-starter</artifactId>
      <version>3.0.3</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring-boot.version}</version>
        <configuration>
          <mainClass>com.orchids.signinbybitmap.SignByBitmapApplication</mainClass>
          <skip>true</skip>
        </configuration>
        <executions>
          <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

配置文件

# 应用服务 WEB 访问端口
server:
  port: 8080

spring:
  redis:
    host: localhost
    port: 6379
    password: 6379
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

knife4j配置类

package com.orchids.signinbybitmap.web.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
//import springfox.documentation.swagger2.annotations.EnableSwagger2;


/**
 * @ Author qwh
 * @ Date 2024/7/5 13:08
 */
@Configuration
//@EnableSwagger2
public class knife4jConfiguration {
    @Bean
    public Docket webApiConfig(){
        // 创建Docket实例
        Docket webApi = new Docket(DocumentationType.SWAGGER_2)
        .groupName("StudentApi")
        .apiInfo(webApiInfo())
        .select()
        // 选择需要文档化的API,只显示指定包下的页面
        .apis(RequestHandlerSelectors.basePackage("com.orchids.signinbybitmap"))
        // 指定路径匹配规则,只对/student开头的路径进行文档化
        .paths(PathSelectors.regex("/User/.*"))
        .build();
        return webApi;
    }

    /**
     * 构建API信息
     * 本函数用于创建并返回一个ApiInfo对象,该对象包含了API文档的标题、描述、版本以及联系方式等信息。
     * @return 返回构建好的ApiInfo对象
     */
    private ApiInfo webApiInfo(){
        // 使用ApiInfoBuilder构建API信息
        return new ApiInfoBuilder()
        .title("Student message API文档") // 设置文档标题
        .description("本文档描述了Swagger2测试接口定义") // 设置文档描述
        .version("1.0") // 设置文档版本号
        .contact(new Contact("nullpointer", "http://blog.nullpointer.love", "nullpointer2024@gmail.com")) // 设置联系人信息
        .build(); // 构建并返回ApiInfo对象
    }
}

controller
package com.orchids.signinbybitmap.web.controller;

import com.orchids.signinbybitmap.web.domain.result.Result;
import com.orchids.signinbybitmap.web.domain.vo.SignResultVO;
import com.orchids.signinbybitmap.web.service.SignService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

/**
 * @ Author qwh
 * @ Date 2024/7/5 13:01
 */
@Api(tags = "签到相关接口")
@RestController
@RequestMapping("/User")
@RequiredArgsConstructor
public class SignController {
    private final SignService signService;
    @ApiOperation("签到")
    @GetMapping("Sign")
    public Result<SignResultVO> AddSignRecords() {
        return signService.AddSignRecords();
    }
}

service
package com.orchids.signinbybitmap.web.service;

import com.orchids.signinbybitmap.web.domain.result.Result;
import com.orchids.signinbybitmap.web.domain.vo.SignResultVO;

/**
 * @ Author qwh
 * @ Date 2024/7/5 13:35
 */
public interface SignService {
    Result<SignResultVO> AddSignRecords();
}

可以扩展其他功能

package com.orchids.signinbybitmap.web.service.impl;

import com.orchids.signinbybitmap.web.domain.result.Result;
import com.orchids.signinbybitmap.web.domain.vo.SignResultVO;
import com.orchids.signinbybitmap.web.exception.SignException;
import com.orchids.signinbybitmap.web.service.SignService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedList;
import java.util.List;

/**
 * @ Author qwh
 * @ Date 2024/7/5 13:35
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SignServiceImpl implements SignService {
    private final String SIGN_UID= "sign:uid:";

    private final StringRedisTemplate redisTemplate;
    @Override
    public Result<SignResultVO> AddSignRecords() {
        SignResultVO vo = new SignResultVO();
        //获取签到用户
        Long userId = 1388888L;
        //获取签到日期
        LocalDateTime now = LocalDateTime.now();
        String format = now.format(DateTimeFormatter.ofPattern(":yyyy-MM-dd"));
        //设置redisKey   sign:uid:1388888:2024-07-05 5 1
        String key = SIGN_UID + userId.toString() + format;
        //计算签到偏移量
        int offset = now.getDayOfMonth() - 1;
        //添加签到记录到redis
        Boolean sign = redisTemplate.opsForValue().setBit(key, offset, true);
        if (sign){
            throw new SignException("亲!您今天已经登录过哟 (❁´◡`❁)",520);
        }
        //计算连续签到天数
        int day = now.getDayOfMonth();
        int continueDays = countSignDays(key,day);
        int rewardPoints = 0;
        switch (continueDays){
            case 2:
                rewardPoints = 10;
                break;
            case 4:
                rewardPoints=20;
                break;
            case 6:
                rewardPoints = 40;
                break;
        }
        //获取签到详情信息
        List<Integer> signDayRecord = SignRecords(userId,key,day);
        vo.setUserId(userId.intValue());
        vo.setSignDays(continueDays);
        vo.setRewardPoints(rewardPoints);
        vo.setSignRecords(signDayRecord);
        return Result.ok(vo);
    }

    /**
     * 获取连续签到天数
     * @param key
     * @param days
     * @return
     */
    private int countSignDays(String key, int days) {

        //从redis读取签到记录
        List<Long> nums = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(days)).valueAt(0));
        //计算签到次数
        int num = nums.get(0).intValue();
        //num与1进行与计算得到二进制的末尾 当末尾为1 说明签到 为0 说明没有签到
        int result = 0;
        while ((num & 1) == 1) {
            result++;
            num = num >>>1;
        }
        //返回签到结果
        return result;
    }

    /**
     * 获取签到详情
     * @param userId
     * @param key
     * @param day
     * @return
     */
    private List<Integer> SignRecords(Long userId, String key, int day) {
        //获取从redis中获取登录信息

        List<Long> sign = redisTemplate.opsForValue().bitField(key, BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(day)).valueAt(0));

        int num = sign.get(0).intValue();
        LinkedList<Integer> result = new LinkedList<>();
        while (day > 0) {
            result.addFirst(num & 1);
            num = num >>> 1;
            day--;
        }
        return result;
    }
}

其他类
package com.orchids.signinbybitmap.web.domain.result;

import lombok.Data;

/**
 * @ Author qwh
 * @ Date 2024/7/5 16:52
 */
@Data
public class Result<T> {
    //返回码
    private Integer code;

    //返回消息
    private String message;

    //返回数据
    private T data;

    public Result() {
    }

    private static <T> Result<T> build(T data) {
        Result<T> result = new Result<>();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static <T> Result<T> build(T body, ResultCode resultCode) {
        Result<T> result = build(body);
        result.setCode(resultCode.getCode());
        result.setMessage(resultCode.getMessage());
        return result;
    }


    public static <T> Result<T> ok(T data) {
        return build(data, ResultCode.SUCCESS);
    }

    public static <T> Result<T> ok() {
        return Result.ok(null);
    }
    public static <T> Result<T> fail(Integer code, String message) {
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static <T> Result<T> fail() {
        return build(null, ResultCode.FAIL);
    }
}

package com.orchids.signinbybitmap.web.domain.result;

import lombok.Getter;

/**
 * @ Author qwh
 * @ Date 2024/7/5 16:54
 */
@Getter
public enum ResultCode {

    SUCCESS(200, "成功"),
    FAIL(201, "失败"),
    PARAM_ERROR(202, "参数不正确"),
    SERVICE_ERROR(203, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    ILLEGAL_REQUEST(205, "非法请求"),
    REPEAT_SUBMIT(206, "重复提交"),
    DELETE_ERROR(207, "请先删除子集"),

    ADMIN_ACCOUNT_EXIST_ERROR(301, "账号已存在"),
    ADMIN_CAPTCHA_CODE_ERROR(302, "验证码错误"),
    ADMIN_CAPTCHA_CODE_EXPIRED(303, "验证码已过期"),
    ADMIN_CAPTCHA_CODE_NOT_FOUND(304, "未输入验证码"),
    ADMIN_ACCOUNT_NOT_EXIST(330,"用户不存在"),


    ADMIN_LOGIN_AUTH(305, "未登陆"),
    ADMIN_ACCOUNT_NOT_EXIST_ERROR(306, "账号不存在"),
    ADMIN_ACCOUNT_ERROR(307, "用户名或密码错误"),
    ADMIN_ACCOUNT_DISABLED_ERROR(308, "该用户已被禁用"),
    ADMIN_ACCESS_FORBIDDEN(309, "无访问权限"),
    APP_LOGIN_AUTH(501, "未登陆"),
    APP_LOGIN_PHONE_EMPTY(502, "手机号码为空"),
    APP_LOGIN_CODE_EMPTY(503, "验证码为空"),
    APP_SEND_SMS_TOO_OFTEN(504, "验证法发送过于频繁"),
    APP_LOGIN_CODE_EXPIRED(505, "验证码已过期"),
    APP_LOGIN_CODE_ERROR(506, "验证码错误"),
    APP_ACCOUNT_DISABLED_ERROR(507, "该用户已被禁用"),


    TOKEN_EXPIRED(601, "token过期"),
    TOKEN_INVALID(602, "token非法");


    private final Integer code;

    private final String message;

    ResultCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}
package com.orchids.signinbybitmap.web.domain.vo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.models.auth.In;
import lombok.Data;

import java.util.List;

/**
 * @ Author qwh
 * @ Date 2024/7/5 13:36
 */
@Data
@ApiModel(description = "签到结果")
public class SignResultVO {

    @ApiModelProperty("签到人")
    private Integer UserId;

    @ApiModelProperty("签到得分")
    private Integer signPoints = 1;

    @ApiModelProperty("连续签到天数")
    private Integer signDays;

    @ApiModelProperty("连续签到奖励积分,连续签到超过7天以上才有奖励")
    private Integer rewardPoints;

    @ApiModelProperty("签到详细信息")
    private List<Integer> signRecords;


}

package com.orchids.signinbybitmap.web.exception;

import com.orchids.signinbybitmap.web.domain.result.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @ Author qwh
 * @ Date 2024/7/5 16:51
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
        e.printStackTrace();
        return Result.fail();
    }
    @ExceptionHandler(SignException.class)
    @ResponseBody
    public Result error(SignException e){
        e.printStackTrace();
        return Result.fail(e.getCode(), e.getMessage());
    }
}

package com.orchids.signinbybitmap.web.exception;

import lombok.Data;

/**
 * @ Author qwh
 * @ Date 2024/7/5 16:47
 */
@Data
public class SignException extends RuntimeException{
    //异常状态码
    private Integer code;
    /**
     * 通过状态码和错误消息创建异常对象
     * @param message
     * @param code
     */
    public SignException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    @Override
    public String toString() {
        return "SignException{" +
                "code=" + code +
                ", message=" + this.getMessage() +
                '}';
    }
}

package com.orchids.signinbybitmap;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class SignByBitmapApplication {

    public static void main(String[] args) {
        SpringApplication.run(SignByBitmapApplication.class, args);
    }

}

测试结果

image.png

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/776622.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

物联网行业等保有什么要求

中国网络安全等级保护制度&#xff08;简称“等保”&#xff09;对物联网行业有特定的要求&#xff0c;以确保物联网系统的安全性。等保2.0在原有安全通用要求的基础上&#xff0c;增加了针对新技术如云计算、物联网、移动互联网等的扩展要求。以下是一些关键的物联网安全扩展要…

C语言编译和编译预处理

编译预处理 • 编译是指把高级语言编写的源程序翻译成计算机可识别的二进制程序&#xff08;目标程序&#xff09;的过程&#xff0c;它由编译程序完成。 • 编译预处理是指在编译之前所作的处理工作&#xff0c;它由编译预处理程序完成 在对一个源程序进行编译时&#xff0c;…

小红书矩阵系统源码:赋能内容创作与电商营销的创新工具

在内容驱动的电商时代&#xff0c;小红书凭借其独特的社区氛围和用户基础&#xff0c;成为品牌营销和个人创作者不可忽视的平台。小红书矩阵系统源码&#xff0c;作为支撑这一平台的核心技术&#xff0c;提供了一系列的功能和优势&#xff0c;助力用户在小红书生态中实现更高效…

简体一键转繁体,智能命名神器,轻松将文件名翻译为繁体中文并精准复制至指定文件夹!

在信息爆炸的时代&#xff0c;文件管理和命名变得愈发重要。你是否曾经因为文件名混乱、不易识别而头疼不已&#xff1f;是否想要让文件名称更符合你的阅读习惯&#xff0c;却又因为语言转换的繁琐而望而却步&#xff1f;今天&#xff0c;我们为你带来了一款文件改名神器——文…

S32DS S32 Design Studio for S32 Platform 3.5 软件安装离线激活

问题描述 重新下载安装 NXP s32系列芯片的集成开发环境&#xff08;IDE&#xff09; S32DS S32 Design Studio&#xff0c;当前版本 S32 Design Studio for S32 Platform 3.5&#xff0c;安装时遇到激活问题 在线激活&#xff0c;激活码哪里来&#xff1f; s32ds 不是免费的&a…

python: create Envircomnet in Visual Studio Code 创建虚拟环境

先配置python开发环境 1.在搜索栏输入“>" 或是用快捷组合键ctrlshiftP键 就会显示”>",再输入"python:" 选择已经安装好的python的版本,选定至当前项目中&#xff0c;都是按回车 就可以看到创建了一个虚拟环境的默认的文件夹名".venv" 2 …

Mybatis原生使用

一、MyBatis初次使用 2.1 环境搭建步骤 MyBatis 的 API &#xff1a; https://mybatis.org/mybatis-3/zh/getting-started.html 1.引入依赖包 2.准备核心配置件 db.properties drivercom.mysql.cj.jdbc.Driver urljdbc:mysql://123.57.206.19:3306/demo?useUnicodetrue&am…

PMP–知识卡片--SWOT分析

记忆 SWOT&#xff1a;优劣鸡血&#xff1b; 记忆2&#xff1a; “两条线画成四象限”&#xff0c;即自身优势S/劣势W外部机会O/威胁T&#xff0c;如图&#xff1a; 定义 SWOT分析从优势、劣势、机会、威胁四个角度进行分析&#xff0c;常用于战略管理、项目风险识别。 项…

关于 Mac 系统 .DS_store 文件的起源

原文&#xff1a;Arno - 2006.10.01 &#xff08;前排提醒&#xff1a;可以在 .gitignore 中添加 .DS_Store&#xff0c;否则 git 仓库会存储这个和项目无关的文件。&#xff09; 如果你是 Mac 用户&#xff0c;曾经将文件从 Mac 传输到 Windows&#xff0c;那么可能对 .DS_S…

渲染回调函数将音频传给音频单元

渲染回调函数将音频传给音频单元 渲染回调函数将音频传给音频单元了解音频单元渲染回调函数 渲染回调函数将音频传给音频单元 要将音频从磁盘或内存提供到音频单元输入总线&#xff0c;需使用符合 AURenderCallback 原型的渲染回调函数进行传输。当需要另一片样本帧时&#xf…

实现模型贴图的移动缩放旋转

技术&#xff1a;threejscanvasfabric 效果图&#xff1a; 原理&#xff1a;threejs中没有局部贴图的效果&#xff0c;只能通过map 的方式贴到模型上&#xff0c;所以说换一种方式来实现&#xff0c;通过canvasfabric来实现图片的移动缩放旋转&#xff0c;然后将整个画布以map…

【智能算法应用】麻雀搜索算法SSA优化Kmeans图像分割

目录 1.算法原理2.数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】麻雀搜索算法&#xff08;SSA&#xff09;原理及实现 2.数学模型 Kmeans是一种无监督的聚类算法,由于参数简洁,时间复杂度低已成功应用于图像分割,取得了良好的分割效果。但传统的 K 均值聚…

Go-知识测试-性能测试

Go-知识测试-性能测试 1. 定义2. 例子3. testing.common 测试基础数据4. testing.TB 接口5. 关键函数5.1 testing.runBenchmarks5.2 testing.B.runN5.3 testing.B.StartTimer5.4 testing.B.StopTimer5.5 testing.B.ResetTimer5.6 testing.B.Run5.7 testing.B.run15.8 testing.B…

无人机便携式侦测干扰设备(定全向)技术详解

无人机便携式侦测干扰设备&#xff08;定全向&#xff09;是一种专门针对无人机进行侦测和干扰的设备。它具备定向和全向两种工作模式&#xff0c;能够覆盖较宽的频率范围&#xff0c;有效侦测并干扰无人机与遥控器之间的通信信号&#xff0c;从而达到控制或驱离无人机的目的。…

1999-2022年企业持续绿色创新水平数据

企业持续绿色创新水平数据为研究者提供了评估企业在绿色技术领域创新持续性和能力的重要视角。以下是对企业持续绿色创新水平数据的介绍&#xff1a; 数据简介 定义&#xff1a;企业持续绿色创新水平反映了企业在一定时期内绿色专利申请的持续性和创新能力。计算方法&#xf…

收银系统源码-营销活动-积分商城

1. 功能描述 营运抽奖&#xff1a;智慧新零售收银系统&#xff0c;线上商城的营销插件&#xff0c;由商户运营&#xff0c;用户通过多种渠道可以获取积分&#xff0c;不仅支持在收银端抵用&#xff0c;还可以在积分商城内兑换优惠券或者真实商品&#xff0c;提升会员活跃度&am…

计算机图形学入门24:材质与外观

1.前言 想要得到一个漂亮准确的场景渲染效果&#xff0c;不只需要物理正确的全局照明算法&#xff0c;也要了解现实中各种物体的表面外观和在图形学中的模拟方式。而物体的外观和材质其实就是同一个意思&#xff0c;不同的材质在光照下就会表现出不同的外观&#xff0c;所以外观…

CH09_JS的循环控制语句

第9章&#xff1a;Javascript循环控制语句 本章目标 掌握break关键字的使用掌握continue关键字的使用 课程回顾 for循环的特点和语法while循环的特点和语法do-while循环的特点和语法三个循环的区别 讲解内容 1. break关键字 为什么要使用break关键字 生活中&#xff0c;描…

MongoDB集群搭建-最简单

目录 前言 一、分片概念 二、搭建集群的步骤 总结 前言 MongoDB分片&#xff08;Sharding&#xff09;是一种水平扩展数据库的方法&#xff0c;它允许将数据分散存储在多个服务器上&#xff0c;从而提高数据库的存储容量和处理能力。分片是MongoDB为了应对大数据量和高吞吐量需…

13 - Python网络编程入门

网络编程入门 计算机网络基础 计算机网络是独立自主的计算机互联而成的系统的总称&#xff0c;组建计算机网络最主要的目的是实现多台计算机之间的通信和资源共享。今天计算机网络中的设备和计算机网络的用户已经多得不可计数&#xff0c;而计算机网络也可以称得上是一个“复…