会员登录 - 用户注册 - 设为首页 - 加入收藏 - 网站地图 网上购物系统源代码!
当前位置:首页 > 焦点 > 网上购物系统源代码 正文

网上购物系统源代码

时间:2026-10-17 06:34:03 来源:烟消火灭网 作者:知识 阅读:874次
```html 网上购物系统源代码 · 技术控笔记

网上购物系统源代码

后端 · 前端 · 数据库 技术拆解 2025.04

一套能跑起来的购物系统,核心就三块:用户能登、购物商品能看、系统订单能下。源代我见过太多人一上来就想搞微服务、网上搞分布式,购物结果连购物车合并逻辑都写不利索。系统直接看代码——下面这个 Cart 类,源代处理了商品添加、网上数量修改、购物删除和总价计算,系统前后端都靠它吃饭。源代

// cart.js —— 购物车核心逻辑,网上别小看这几十行
class Cart {
  constructor() {
    this.items = new Map(); // key: productId,购物 value: { product, qty}
  }

  addItem(product, qty = 1) {
    const existing = this.items.get(product.id);
    if (existing) {
      existing.qty += qty;
    } else {
      this.items.set(product.id, { product, qty });
    }
  }

  getTotal() {
    let sum = 0;
    for (let item of this.items.values()) {
      sum += item.product.price * item.qty;
    }
    return sum;
  }
}

注意那个 Map 的选型——不是随便挑的。用普通对象存商品 ID 当键,系统数字会被转成字符串,后面做深比较容易翻车。Map 保留键的类型,而且迭代顺序稳定。这算个细节,但线上环境里省掉不少 bug。

后端用 Node.js + Express 搭起来最快。商品列表接口二十行搞定,但订单接口就得小心。下面这段是下单时的库存扣减逻辑,用了 MySQL 事务,不然超卖能把你搞崩溃。

// orderController.js —— 下单扣库存,事务不能省
async createOrder(req, res) {
  const conn = await pool.getConnection();
  try {
    await conn.beginTransaction();
    for (let item of req.body.items) {
      const [rows] = await conn.query(
        'SELECT stock FROM products WHERE id = ? FOR UPDATE',
        [item.productId]
      );
      if (rows[0].stock < item.qty) throw new Error('库存不足');
      await conn.query(
        'UPDATE products SET stock = stock - ? WHERE id = ?',
        [item.qty, item.productId]
      );
    }
    await conn.commit();
    res.json({ code: 0, msg: '下单成功' });
  } catch (err) {
    await conn.rollback();
    res.status(400).json({ code: 1, msg: err.message });
  } finally {
    conn.release();
  }
}

看那个 FOR UPDATE,行锁。不加的话,两个人同时买最后一件商品,两个事务都读到库存 1,都去扣减,最后库存变成 -1。这种事故我亲眼见过,凌晨两点被叫起来修数据。所以别嫌麻烦,事务加锁是底线。

一个坑: 很多人把库存扣减放在应用层用 Redis 做原子操作,但数据库和缓存双写一致性能把你玩死。小系统直接用 MySQL 行锁,简单可靠。

前端商品列表用 React 写,逻辑不复杂。但图片懒加载和分页得做,不然商品一多,首屏加载慢得用户直接关页面。下面这个 ProductList 组件,用了 IntersectionObserver 做图片懒加载,代码不多,效果立竿见影。

// ProductList.jsx —— 懒加载 + 分页加载更多
function ProductList() {
  const [products, setProducts] = useState([]);
  const [page, setPage] = useState(1);
  const loaderRef = useRef();

  useEffect(() => {
    fetch(`/api/products?page=${ page}&limit=20`)
      .then(res => res.json())
      .then(data => setProducts(prev => [...prev, ...data]));
  }, [page]);

  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting) setPage(p => p + 1);
    }, { threshold: 0.1 });
    if (loaderRef.current) observer.observe(loaderRef.current);
    return () => observer.disconnect();
  }, []);

  return (
    <div className="grid">
      { products.map(p => <ProductCard key={ p.id} data={ p} />)}
      <div ref={ loaderRef}>加载中...</div>
    </div>
  );
}

数据库建表也有讲究。商品表 products 里,price 用 DECIMAL(10,2),别用 FLOAT。浮点数算钱,0.1 + 0.2 不等于 0.3,财务对账能把你逼疯。订单表 orders 和订单项表 order_items 分开,别把商品信息冗余进订单表——商品改价改名字,历史订单不能跟着变。

最后说部署。前端打包扔 Nginx,后端 Node 用 PM2 守护,数据库单独一台机器。别把所有东西塞进一台 1 核 2G 的服务器,并发一上来直接 OOM。我见过有人用 pm2 start app.js -i max 在单核机器上开满进程,结果上下文切换把 CPU 吃光。根据核数来,一般 -i 2 就够了。

```

(责任编辑:综合)

相关内容
  • 兰州反渗透
  • 建站CMS
  • 二进制安全
  • 404notfound网站进入页面
  • tracemoe官网入口
  • 海南企业黄页官网
  • 网页倒计时器
  • 下列工具中那几个是漏洞扫描器
推荐内容
  • 正版全平台内容系统骗局
  • 禅道提交bug流程
  • 投标网站
  • 高频彩票平台
  • 社区论坛网站
  • 黑帽风险