当前位置: 代码网 > it编程>编程语言>Javascript > mysql + nest.js  加锁搞并发问题的实现

mysql + nest.js  加锁搞并发问题的实现

2026年03月08日 Javascript 我要评论
我给你一个 真实项目级的例子:用 nestjs + mysql 原生 sql 实现 秒杀库存扣减,并解决 高并发超卖问题。这个例子是很多电商系统的核心逻辑。一、数据库设计商品表create table

我给你一个 真实项目级的例子
nestjs + mysql 原生 sql 实现 秒杀库存扣减,并解决 高并发超卖问题

这个例子是很多电商系统的核心逻辑。

一、数据库设计

商品表

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
);

初始化库存

insert into goods (name, stock, price)
values ('iphone 15', 10, 8999);

二、问题:高并发超卖

如果代码这样写:

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 个请求会出现:

库存10
卖出去100

因为:

读取库存不是原子操作

三、正确方案一(推荐):原子 sql

最推荐的写法:

update goods
set stock = stock - 1
where id = ? and stock > 0;

优点:

单条 sql
原子操作
不会超卖
性能极高

四、nestjs 原生 sql 实现

使用 mysql 连接池。

安装:

npm install mysql2

数据库服务

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 扣库存(原子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: '库存不足'
      }
    }

    // 2 创建订单
    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)

  }

}

七、执行流程(高并发)

1000个请求:

update goods set stock = stock - 1 where id=1 and stock>0

mysql 内部会保证:

库存10

前10个请求成功
990个失败

不会出现:

stock = -1

八、真实大厂架构(完整版)

真正秒杀系统通常是这样:

用户请求
   ↓
nginx
   ↓
redis 判断库存
   ↓
消息队列 (kafka / rabbitmq)
   ↓
nestjs 消费
   ↓
mysql 扣库存

作用:

redis      防止打爆数据库
mq         削峰
mysql      最终一致

九、如果必须用 mysql lock

有些复杂业务必须用:

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: '库存不足' }
  }

  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: '购买成功' }

} catch (err) {

  await conn.rollback()
  throw err

} finally {

  conn.release()

}

十、什么时候用哪种方案

方案推荐度场景
原子 update⭐⭐⭐⭐⭐秒杀、库存
事务 + for update⭐⭐⭐复杂业务
redis + mq⭐⭐⭐⭐⭐⭐超高并发

💡 我再告诉你一个 90% 后端不知道的优化技巧:

mysql 秒杀最强写法其实是:

update goods 
set stock = stock - 1 
where id = 1 and stock > 0
limit 1;

原因:

防止误更新
锁范围更小

到此这篇关于mysql + nest.js 加锁搞并发问题的实现的文章就介绍到这了,更多相关mysql nest.js 加锁并发内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com