️测试问我:为啥阅读量计数这么简单的功能你都能写出bug?

2024-05-08 00:28

本文主要是介绍️测试问我:为啥阅读量计数这么简单的功能你都能写出bug?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

可乐他们团队最近在做一个文章社区平台,由于人手不够,后端部分也是由前端同学来实现,使用的是 nest

今天他接到了一个需求,就是在用户点开文章详情的时候,把阅读量 +1 ,这里不需要判断用户是否阅读过,无脑 +1 就行。

它心想:这么简单,这不是跟 1+1 一样么。

往期文章

仓库地址

  • 切图仔做全栈:React&Nest.js 社区平台(一)——基础架构与邮箱注册、JWT 登录实现
  • 切图仔做全栈:React&Nest.js社区平台(二)——👋手把手实现优雅的鉴权机制
  • React&Nest.js全栈社区平台(三)——🐘对象存储是什么?为什么要用它?
  • React&Nest.js社区平台(四)——✏️文章发布与管理实战
  • React&Nest.js全栈社区平台(五)——👋封装通用分页Service实现文章流与详情
  • 领导问我:为什么一个点赞功能你做了五天?

初版实现

我们用的 orm 框架是 typeorm ,然后他看了一眼官方文档,下面是一个更新的例子。

image.png

文章表里有一个字段 views ,表示该文章的阅读量。那我是不是把这篇文章的 views 取出来,然后 +1 ,再塞回去就可以了呢?

啪一下,就写出了下面这样的代码:

  async addView(articleId: number) {const entity = await this.articleRepository.findOne({where: { id: articleId },select: ['views', 'id'],});entity.views = entity.views + 1;await this.articleRepository.save(entity);}

然后就美滋滋的提测,继续摸鱼去了。

并发bug

不出意外的话意外就要发生了,测试下午就找到了可乐,说这个实现有 bug ,具体复现是在并发压测的时候。

这里用一个 node 脚本来模拟一下并发的请求:

import axios from "axios";const axiosInstance = axios.create({withCredentials: true,headers: {Cookie: "your cookie",},
});for (let i = 0; i < 10; i++) {axiosInstance.get("http://localhost:3000/api/articles/getArticleInfo?id=2");
}

本来应该阅读量加 10 的,结果只加了 1

image.png

可乐当时脑瓜子嗡嗡的,这还能有 bug

具体来说,这是 mysql 处理并发的机制—— MVCC ,它有几种默认的隔离级别。默认的隔离级别是可重复读,在可重复读的隔离级别下,会出现以下这种情况:

image.png

也就是说,当多个客户端同时读取相同的文章实体,然后分别对其浏览次数进行增加,并尝试保存回数据库,这有可能前面的提交会被后提交的操作覆盖,导致阅读量的的更新丢失。

update…set

最简单的解决方案就是不要取出来再更新,而是使用 mysqlupdate...set 语句,它本身自带的锁可以帮我们规避掉这种问题。

await this.articleRepository.query('UPDATE articles SET views = views + 1 WHERE id = ?',[articleId],
);

这一次再用测试脚本去跑的时候,发现是没有问题的了,加的次数是对的。

这篇关于️测试问我:为啥阅读量计数这么简单的功能你都能写出bug?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968811

相关文章

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

SpringKafka消息发布之KafkaTemplate与事务支持功能

《SpringKafka消息发布之KafkaTemplate与事务支持功能》通过本文介绍的基本用法、序列化选项、事务支持、错误处理和性能优化技术,开发者可以构建高效可靠的Kafka消息发布系统,事务支... 目录引言一、KafkaTemplate基础二、消息序列化三、事务支持机制四、错误处理与重试五、性能优

SpringIntegration消息路由之Router的条件路由与过滤功能

《SpringIntegration消息路由之Router的条件路由与过滤功能》本文详细介绍了Router的基础概念、条件路由实现、基于消息头的路由、动态路由与路由表、消息过滤与选择性路由以及错误处理... 目录引言一、Router基础概念二、条件路由实现三、基于消息头的路由四、动态路由与路由表五、消息过滤

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

一文详解SpringBoot响应压缩功能的配置与优化

《一文详解SpringBoot响应压缩功能的配置与优化》SpringBoot的响应压缩功能基于智能协商机制,需同时满足很多条件,本文主要为大家详细介绍了SpringBoot响应压缩功能的配置与优化,需... 目录一、核心工作机制1.1 自动协商触发条件1.2 压缩处理流程二、配置方案详解2.1 基础YAML

springboot简单集成Security配置的教程

《springboot简单集成Security配置的教程》:本文主要介绍springboot简单集成Security配置的教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录集成Security安全框架引入依赖编写配置类WebSecurityConfig(自定义资源权限规则

如何使用Python实现一个简单的window任务管理器

《如何使用Python实现一个简单的window任务管理器》这篇文章主要为大家详细介绍了如何使用Python实现一个简单的window任务管理器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 任务管理器效果图完整代码import tkinter as tkfrom tkinter i