最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mysql + nest.js  加鎖搞并發(fā)問(wèn)題的實(shí)現(xiàn)

 更新時(shí)間:2026年03月08日 08:29:55   作者:張洪權(quán)  
本文主要介紹了使用NestJS和MySQL實(shí)現(xiàn)秒殺系統(tǒng)的庫(kù)存扣減,并解決了高并發(fā)超賣問(wèn)題,通過(guò)原子SQL、NestJS原生SQL實(shí)現(xiàn)以及使用Redis和消息隊(duì)列等方案,可以有效提高系統(tǒng)的性能和穩(wěn)定性,

我給你一個(gè) 真實(shí)項(xiàng)目級(jí)的例子
NestJS + MySQL 原生 SQL 實(shí)現(xiàn) 秒殺庫(kù)存扣減,并解決 高并發(fā)超賣問(wèn)題。

這個(gè)例子是很多電商系統(tǒng)的核心邏輯。

一、數(shù)據(jù)庫(kù)設(shè)計(jì)

商品表

CREATE TABLE goods (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(100),
  stock INT NOT NULL,
  price DECIMAL(10,2),
  create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

訂單表

CREATE TABLE orders (
  id INT PRIMARY KEY AUTO_INCREMENT,
  user_id INT,
  goods_id INT,
  create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

初始化庫(kù)存

INSERT INTO goods (name, stock, price)
VALUES ('iphone 15', 10, 8999);

二、問(wèn)題:高并發(fā)超賣

如果代碼這樣寫(xiě):

const goods = await db.query('SELECT * FROM goods WHERE id = ?', [id])

if (goods.stock > 0) {
  await db.query('UPDATE goods SET stock = stock - 1 WHERE id = ?', [id])
}

1000 個(gè)請(qǐng)求會(huì)出現(xiàn):

庫(kù)存10
賣出去100

因?yàn)椋?/p>

讀取庫(kù)存不是原子操作

三、正確方案一(推薦):原子 SQL

最推薦的寫(xiě)法:

UPDATE goods
SET stock = stock - 1
WHERE id = ? AND stock > 0;

優(yōu)點(diǎn):

單條 SQL
原子操作
不會(huì)超賣
性能極高

四、NestJS 原生 SQL 實(shí)現(xiàn)

使用 MySQL 連接池。

安裝:

npm install mysql2

數(shù)據(jù)庫(kù)服務(wù)

import { Injectable } from '@nestjs/common'
import * as mysql from 'mysql2/promise'

@Injectable()
export class MysqlService {

  pool = mysql.createPool({
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'test',
    connectionLimit: 10
  })

  async query(sql: string, params?: any[]) {
    const [rows] = await this.pool.execute(sql, params)
    return rows
  }

}

五、秒殺 Service

import { Injectable } from '@nestjs/common'
import { MysqlService } from './mysql.service'

@Injectable()
export class SeckillService {

  constructor(private db: MysqlService) {}

  async buy(userId: number, goodsId: number) {

    // 1 扣庫(kù)存(原子SQL)
    const result: any = await this.db.query(
      `UPDATE goods 
       SET stock = stock - 1 
       WHERE id = ? AND stock > 0`,
      [goodsId]
    )

    if (result.affectedRows === 0) {
      return {
        message: '庫(kù)存不足'
      }
    }

    // 2 創(chuàng)建訂單
    await this.db.query(
      `INSERT INTO orders (user_id, goods_id) VALUES (?, ?)`,
      [userId, goodsId]
    )

    return {
      message: '秒殺成功'
    }

  }

}

六、Controller

import { Controller, Post, Body } from '@nestjs/common'
import { SeckillService } from './seckill.service'

@Controller('seckill')
export class SeckillController {

  constructor(private seckillService: SeckillService) {}

  @Post('buy')
  async buy(@Body() body) {

    const { userId, goodsId } = body

    return this.seckillService.buy(userId, goodsId)

  }

}

七、執(zhí)行流程(高并發(fā))

1000個(gè)請(qǐng)求:

UPDATE goods SET stock = stock - 1 WHERE id=1 AND stock>0

MySQL 內(nèi)部會(huì)保證:

庫(kù)存10

前10個(gè)請(qǐng)求成功
990個(gè)失敗

不會(huì)出現(xiàn):

stock = -1

八、真實(shí)大廠架構(gòu)(完整版)

真正秒殺系統(tǒng)通常是這樣:

用戶請(qǐng)求
   ↓
Nginx
   ↓
Redis 判斷庫(kù)存
   ↓
消息隊(duì)列 (Kafka / RabbitMQ)
   ↓
NestJS 消費(fèi)
   ↓
MySQL 扣庫(kù)存

作用:

Redis      防止打爆數(shù)據(jù)庫(kù)
MQ         削峰
MySQL      最終一致

九、如果必須用 MySQL Lock

有些復(fù)雜業(yè)務(wù)必須用:

SELECT * FROM goods WHERE id = 1 FOR UPDATE;

NestJS 示例:

const conn = await this.db.pool.getConnection()

try {

  await conn.beginTransaction()

  const [goods]: any = await conn.query(
    'SELECT * FROM goods WHERE id = ? FOR UPDATE',
    [goodsId]
  )

  if (goods.length === 0 || goods[0].stock <= 0) {
    await conn.rollback()
    return { message: '庫(kù)存不足' }
  }

  await conn.query(
    'UPDATE goods SET stock = stock - 1 WHERE id = ?',
    [goodsId]
  )

  await conn.query(
    'INSERT INTO orders (user_id, goods_id) VALUES (?, ?)',
    [userId, goodsId]
  )

  await conn.commit()

  return { message: '購(gòu)買(mǎi)成功' }

} catch (err) {

  await conn.rollback()
  throw err

} finally {

  conn.release()

}

十、什么時(shí)候用哪種方案

方案推薦度場(chǎng)景
原子 UPDATE?????秒殺、庫(kù)存
事務(wù) + FOR UPDATE???復(fù)雜業(yè)務(wù)
Redis + MQ??????超高并發(fā)

?? 我再告訴你一個(gè) 90% 后端不知道的優(yōu)化技巧:

MySQL 秒殺最強(qiáng)寫(xiě)法其實(shí)是:

UPDATE goods 
SET stock = stock - 1 
WHERE id = 1 AND stock > 0
LIMIT 1;

原因:

防止誤更新
鎖范圍更小

到此這篇關(guān)于mysql + nest.js 加鎖搞并發(fā)問(wèn)題的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)mysql nest.js 加鎖并發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA鏈接MySQL報(bào)錯(cuò)08001和連接成功后不顯示表的問(wèn)題及解決方法

    IDEA鏈接MySQL報(bào)錯(cuò)08001和連接成功后不顯示表的問(wèn)題及解決方法

    這篇文章主要介紹了IDEA鏈接MySQL報(bào)錯(cuò)08001和連接成功后不顯示表的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • MySQL創(chuàng)建用戶的三種方法

    MySQL創(chuàng)建用戶的三種方法

    在對(duì)MySQL的日常管理和操作中,為了避免有人惡意使用root用戶控制數(shù)據(jù)庫(kù),盡可能地不用或少用 root 用戶登錄系統(tǒng),本文主要介紹了MySQL創(chuàng)建用戶的三種方法,感興趣的可以了解一下
    2023-08-08
  • MySQL版本選擇與安裝超詳細(xì)教程

    MySQL版本選擇與安裝超詳細(xì)教程

    本文主要介紹了MySQL5.5和MySQL8.0的優(yōu)點(diǎn)和缺點(diǎn),并建議大多數(shù)用戶使用最新的穩(wěn)定版本,此外還提供了MySQL的安裝教程和環(huán)境變量的配置方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • 在Windows主機(jī)上定時(shí)備份遠(yuǎn)程VPS(CentOS)數(shù)據(jù)的批處理

    在Windows主機(jī)上定時(shí)備份遠(yuǎn)程VPS(CentOS)數(shù)據(jù)的批處理

    我想在自己的 Windows7 下每天/周運(yùn)行一次備份,就有了這個(gè)小工具
    2012-05-05
  • MySQL系列之七 MySQL存儲(chǔ)引擎

    MySQL系列之七 MySQL存儲(chǔ)引擎

    存儲(chǔ)引擎是數(shù)據(jù)庫(kù)的核心,對(duì)于mysql來(lái)說(shuō),存儲(chǔ)引擎是以插件的形式運(yùn)行的。雖然mysql支持種類繁多的存儲(chǔ)引擎,但是常用的就那么幾種。這篇文章主要給大家介紹MySQL存儲(chǔ)引擎的相關(guān)知識(shí),一起看看吧
    2021-07-07
  • 關(guān)于MYSQL的優(yōu)化全面詳解

    關(guān)于MYSQL的優(yōu)化全面詳解

    一直用了那么久的mysql,雖然了解了一些優(yōu)化方法,但是都是比較簡(jiǎn)單的一些應(yīng)用,這次就系統(tǒng)的了解一下
    2012-09-09
  • MySql如何解決mysql沒(méi)有root用戶問(wèn)題

    MySql如何解決mysql沒(méi)有root用戶問(wèn)題

    文章主要描述了在MySQL中沒(méi)有root用戶的情況如何解決,首先,作者提到由于沒(méi)有root用戶,無(wú)法進(jìn)行后續(xù)的權(quán)限設(shè)置和操作,然后,作者詳細(xì)介紹了創(chuàng)建root用戶并賦予其所有權(quán)限的步驟,包括解決可能遇到的錯(cuò)誤,最后,作者總結(jié)了整個(gè)過(guò)程,并希望大家能夠從中受益
    2025-02-02
  • 深入理解MySQL中的行級(jí)鎖

    深入理解MySQL中的行級(jí)鎖

    行級(jí)鎖加鎖規(guī)則比較復(fù)雜,不同的場(chǎng)景,加鎖的形式是不同的,本文主要介紹了深入理解MySQL中的行級(jí)鎖,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • MySQL數(shù)據(jù)庫(kù)基本SQL語(yǔ)句教程之高級(jí)操作

    MySQL數(shù)據(jù)庫(kù)基本SQL語(yǔ)句教程之高級(jí)操作

    對(duì)MySQL數(shù)據(jù)庫(kù)的查詢,除了基本的查詢外,有時(shí)候需要對(duì)查詢的結(jié)果集進(jìn)行處理,下面這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)庫(kù)基本SQL語(yǔ)句教程之高級(jí)操作的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • 詳解監(jiān)聽(tīng)MySQL的binlog日志工具分析:Canal

    詳解監(jiān)聽(tīng)MySQL的binlog日志工具分析:Canal

    Canal主要用途是基于MySQL數(shù)據(jù)庫(kù)增量日志解析,提供增量數(shù)據(jù)訂閱和消費(fèi),目前主要支持MySQL。接下來(lái)通過(guò)本文給大家介紹監(jiān)聽(tīng)MySQL的binlog日志工具分析:Canal的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2020-10-10

最新評(píng)論

上高县| 腾冲县| 阿瓦提县| 武汉市| 琼结县| 沛县| 大悟县| 会昌县| 垣曲县| 中牟县| 紫金县| 邵阳县| 安福县| 湖州市| 龙游县| 泰宁县| 建湖县| 大渡口区| 深泽县| 屯门区| 响水县| 磴口县| 涿鹿县| 赞皇县| 娱乐| 浮山县| 仪征市| 安龙县| 山东省| 讷河市| 渭源县| 凯里市| 南城县| 开鲁县| 临高县| 青龙| 涟水县| 龙口市| 邮箱| 航空| 九江县|