news 2026/10/22 5:40:07

小程序电影院购票系统:架构、锁座与订单状态机实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
小程序电影院购票系统:架构、锁座与订单状态机实现

简介:这套基于微信小程序与Spring Boot技术栈的电影院购票管理系统源码包,面向计算机类毕业生以及正在学习Java全栈开发的读者。系统采用前后端分离设计,管理后台基于vue与elementui,用户端为微信小程序,后端整合springboot、springmvc、spring、mybatis;角色分为管理员和用户,管理员可对用户、电影、影院、影厅、排片、评论、小吃、广告、订单进行全流程管理,用户端则支持浏览电影、日期选座、在线购票、影院套餐抢购、订单查询与评论互动。资源共计2006个文件,以1413个md文档(设计说明与开发笔记)、411个js文件(前端逻辑)、115个java文件(后端业务)、48个json配置及sql数据库脚本为主,压缩包大小65.25MB,并附带万字设计文档。目前已有30人学习下载,适合作为毕业设计模板或Spring Boot小程序入门实战项目,代码结构清晰、功能覆盖完整,可直接导入运行并二次开发。

1. 小程序电影院购票系统是什么:一套能跑通“选座—下单—出票”闭环的工程模板

拿到“基于小程序的电影院购票管理系统(源码+数据库+万字文档)”这套资料,很多人第一反应是解压、翻文档、找启动步骤。我建议换个顺序:先花半小时把系统边界看清楚。它本质上是“小程序客户端 + 后端接口 + MySQL 数据库 + 管理后台”的四件套工程,核心业务就三件事——选座、下单出票、订单管理。它解决的不是“怎么写一个电影列表页”,而是从 0 到 1 把购票闭环完整跑通,适合毕业设计、课程设计和想在小程序方向快速出作品的人。这里有个反直觉的点:这类项目里最不值得死磕的是页面样式,最容易翻车的是座位并发和订单状态这些看不见的逻辑。

2. 先拆架构和数据库:购票系统的地基是四张表和一条状态机

拆开一套购票系统,先看数据怎么走:小程序端发起请求,后端处理业务规则,数据落进 MySQL,管理端反向录入电影和场次。这条链上真正的难点只有一个——一个座位在同一场次同一时间只能被一个订单占用。要做到这件事,数据库设计和订单状态机必须提前想清楚,否则后面所有“并发抢座”的 bug 都是在这里埋下的。下面按最常见的技术方案拆解:后端 Spring Boot,ORM 用 MyBatis-Plus,数据库 MySQL 5.7 或 8.0。

2.1 小程序端、后端、管理端如何分工,为什么这样分

端职责典型页面或接口
小程序端展示与交互,把用户操作转成接口调用电影列表、选座页、订单页、个人中心
后端服务业务规则与数据一致性控制/api/session、/api/order、/api/pay
管理后台数据录入与运营维护电影上架、场次排片、订单查询、退票处理

小程序端只负责呈现,不碰核心状态。原因很直接:座位占用和订单状态必须由服务端在事务里控制,前端本地缓存完全无法解决并发问题。你不可能让两个用户的手机协商“这个座位谁先点谁得”。选择 Spring Boot,一是这类模板资料最全,二是从依赖注入讲到事务传播,答辩或面试时能讲的东西足够多。也有模板用 Node.js 写后端,业务逻辑等价,我后面的示例按 Java 写,用 Node 的对照着改接口路径和数据库操作即可。

管理端单独做一套是有必要的。排片、上架电影、查看订单这些操作需要登录和权限校验,不能裸奔地放在小程序端让普通用户调用。常见做法是管理端做成一个独立的 Web 页面,技术栈是 Vue 或者简单的 HTML 加 jQuery。如果压缩包里管理端是已经打包好的 dist 目录,你就不需要装 Node 环境;只有需要改前端代码时才需要 Node 16 左右的版本。

2.2 核心表设计:从影厅到订单的关联关系

表名作用关键字段
movie电影信息id, title, poster_url, duration, release_date, status
hall影厅id, name, rows, cols
seat影厅下的物理座位id, hall_id, row_no, col_no
session场次id, movie_id, hall_id, start_time, end_time, price, status
session_seat场次座位状态id, session_id, seat_id, status
user小程序用户id, openid, nickname, phone
t_order订单主表id, order_no, user_id, session_id, total_amount, status, create_time
order_seat订单座位关联id, order_id, session_id, seat_id

这里的重点是理解两条主线。第一条是“影厅到座位”:seat 表属于 hall,一个影厅固定若干排若干列,这张表很少变动。第二条是“电影到场次再到订单”:一部电影在多个影厅多个时间排片,即多条 session 记录;用户买的是某个 session 的某个座位。

为什么不能直接在 seat 表上改售卖状态?因为同一个座位不同场次可以重复卖。昨晚 7 点的《某剧情片》和今晚 9 点的《某动画》用的是同一个影厅同一批座位,状态必须跟着 session 走。所以中间加了一张 session_seat 表,记录“这个场次里这个座位能不能卖”,status 约定为 0 可售、1 已售、2 锁定。这个表的数据量等于所有场次座位数的总和,大影院一天几十个场次很容易上万行,所以要给 (session_id, seat_id) 建唯一索引,这也是后面防并发的第一道物理约束。

订单侧的设计要讲一个细节:很多模板在 t_order 里冗余了 movie_title、hall_name、start_time 这些字段,用来做历史快照。这样做是合理的——订单打印或退款时,即使电影后来改名或场次被删,用户的订单仍能显示当时的完整信息。但你要清楚这是冗余字段,更新 movie 表时不要指望 t_order 跟着变。订单号 order_no 一般用时间戳加随机数生成,或者用雪花算法,别直接拿自增 id 当订单号给用户看,数字太短容易被猜到也显得不专业。

2.3 订单状态机:所有“看不懂的 bug”都藏在状态跳转里

状态值含义说明
0待支付座位已锁定,用户未付款
1已支付支付成功,座位标记已售
2已完成观影结束,订单完结
3已取消未支付超时或用户主动取消
4已退票已支付后退票,座位释放

流转规则是这样的:下单时落状态 0,同时把 session_seat 置为 2 锁定;支付成功后将订单从 0 改 1,同一事务里把 session_seat 从 2 改 1;开场后或管理员手动把 1 改 2 完成;超时未支付或用户取消,0 改 3,座位释放;已支付后退票,1 改 4,座位释放。

这里最重要的原则是:任何订单状态变更,都必须同步处理 session_seat 的可用状态。少了这一步,就会出现“订单已取消,座位却还占着”的灵异现象。状态字段建议用 tinyint,不要用 varchar 存字符串,一是省空间,二是避免“已支付”“已付”“paid”这类脏数据。如果你拿到手的模板里状态是用中文存的,建议先改成数字并加注释,后续所有判断逻辑会清爽很多。

3. 把源码跑起来:从导入数据库到小程序显示的最小步骤

先别急着逐字读那本万字文档。跑通的最小路径只有四条:建库导数据、改配置启后端、工具里打开小程序、浏览器里进管理端。顺序错了会浪费大量时间。比如有人先把小程序端改了半天,后端还没启动,结果页面一片空白,还以为是前端代码写得有问题。

3.1 环境准备:版本配不对,后面全是玄学

组件推荐版本说明
JDK1.8大多数模板基于 Java 8,高版本可能报模块反射错误
Maven3.6.x负责拉依赖,仓库源建议配置为国内镜像
MySQL5.7 或 8.05.7 兼容性最好;8.0 注意驱动和时区参数
微信开发者工具最新稳定版用于打开小程序端源码目录

别用 JDK 17 去跑老模板,常见报错是 IllegalAccessError 和 “不支持的 class 文件版本”,换回 JDK 8 后大部分问题会直接消失。这个坑太经典了,几乎每个群里都有人问。Maven 如果拉依赖特别慢,在 settings.xml 的 mirrors 节点里配置一个国内镜像源,速度快几倍。

管理端如果是 Vue 项目且需要重新编译,那还需要 Node 环境;如果压缩包里只给了打包好的 dist 静态文件,就不需要 Node。先看目录结构再决定装不装,省得白折腾。

3.2 导入数据库:先处理字符集,再处理时区

mysql -u root -p # 建库, 注意使用 utf8mb4, 防止电影简介和用户昵称里的 emoji 变成问号 CREATE DATABASE cinema_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE cinema_db; # 换成你的 SQL 文件实际路径 SOURCE /path/to/cinema_db.sql;

字符集用 utf8mb4 而不是 utf8,原因是 MySQL 的 utf8 最多存 3 字节,存不了 emoji 和生僻字;购票系统的评论、昵称字段很容易踩这个。导入后建议立刻验证三件事:执行 SHOW TABLES; 看表数量是否和文档目录一致;执行 SELECT * FROM movie; 确认有预置电影数据;确认管理端账号在 user 表或 admin 表里存在,后面登录管理后台全靠它。SQL 文件里如果有 DROP TABLE 语句,导入前确认库里没有同名学生数据,别把其他项目的数据冲掉。

3.3 启动后端:连接串、端口、文件路径三个地方必须改

server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/cinema_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver # 海报等文件上传的本地根目录, 改成你自己的绝对路径 file: upload-dir: D:/cinema-upload

URL 里 serverTimezone=Asia/Shanghai 必须加,否则第 5 章那个“场次时间少 8 小时”的坑必踩;useSSL=false 是本地调试省事;allowPublicKeyRetrieval=true 是给 MySQL 8.0 用的,避免 caching_sha2_password 认证方式握手报错。upload-dir 改成本机绝对路径,并保证目录已存在且有写权限,海报上传失败九成是这个问题。

然后启动后端:

cd backend mvn spring-boot:run # 看到 Started XxxApplication 后, 另开一个终端验证接口 curl http://127.0.0.1:8080/api/movie/list

mvn spring-boot:run 会先编译再启动,第一次跑要下载大量依赖,耐心等。如果启动报红,先看 Maven 镜像和 JDK 版本,再看数据库连没连上,顺序别乱。curl 能返回 JSON 说明后端已活;如果模板集成了 Swagger,直接访问 /doc.html 或 /swagger-ui.html,能在浏览器里把全部接口点一遍,这是最快的自测方式。

3.4 小程序端:三个必改项,改完才能看到电影列表

小程序端的网络请求一般封装在 utils/request.js:

// utils/request.js 关键片段 const BASE_URL = 'http://127.0.0.1:8080' // 真机调试时改成电脑的局域网 IP module.exports = (url, data, method = 'GET') => { return new Promise((resolve, reject) => { wx.request({ url: `${BASE_URL}${url}`, data: data, method: method, header: { 'Content-Type': 'application/json' }, success: (res) => { if (res.data.code === 200) { resolve(res.data.data) } else { wx.showToast({ title: res.data.msg, icon: 'none' }) reject(res.data) } }, fail: reject }) }) }

三个必改项,一个都不能漏:第一,BASE_URL 改成你后端的地址,模拟器可以用 127.0.0.1,真机必须用电脑的局域网 IP,比如 http://192.168.1.5:8080;第二,微信开发者工具里的 AppID 用你自己的或官方测试号,别留别人的;第三,开发阶段在“详情—本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”。这三处不改,项目跑起来的表现就是:模拟器一切正常,手机真机白屏。

提示:不校验域名只用于开发调试。上线审核时小程序要求所有请求域名必须是备案且支持 HTTPS 的合法域名,这点后面部署时再处理。

4. 核心业务实现:选座、锁座、下单与余票扣减

这一章是把项目吃透的关键。选座页只是表面,下面三个环节才是系统真正的核心,也是文档里篇幅最多的部分。你如果能把这三段的逻辑讲清楚,答辩时基本不会被动。

4.1 选座页的座位状态渲染:前端只画状态,不判状态

// pages/select-seat/select-seat.js 关键片段 Page({ data: { sessionId: null, rows: 10, cols: 10, seatMap: [], selectedSeats: [] }, onLoad(options) { this.setData({ sessionId: options.sessionId }) this.loadSeats() }, loadSeats() { const baseUrl = getApp().globalData.baseUrl wx.request({ url: `${baseUrl}/api/session/seats`, data: { sessionId: this.data.sessionId }, success: (res) => { const list = res.data.data || [] // 后端返回 [{rowNo, colNo, status}] 扁平数组 const map = [] // 先初始化全为 0(可售), 再用接口结果覆盖 for (let r = 1; r <= this.data.rows; r++) { map[r] = [] for (let c = 1; c <= this.data.cols; c++) map[r][c] = 0 } // 0 可售 / 1 已售 / 2 锁定, 与后端枚举保持一致 list.forEach(item => { if (item.status === 1) map[item.rowNo][item.colNo] = 1 }) this.setData({ seatMap: map }) } }) } })

逻辑说明:座位状态一律以接口返回为准,前端不缓存、不推断。WXML 里把 seatMap 渲染成二维格子,class 按 0、1、2 切换样式即可,已售的置灰、选中的高亮。参数 rows 和 cols 要与影厅表一致,后端接口会校验,不一致时提交订单会被拒绝。这里的常见误解是:前端把座位标灰,用户就买不了。不对,前端只是提示,真正的校验在下单接口里,这也是为什么光改前端代码无法绕过已售座位。

4.2 锁座与下单:事务加行锁加唯一索引,三层防同一座位被秒掉

// 下单核心方法, 务必开启事务 @Transactional(rollbackFor = Exception.class) public String createOrder(Long userId, Long sessionId, List<Long> seatIds) { // 1. 查询场次座位并加行锁, 防止两个请求同时读到 status=0 List<SessionSeat> rows = sessionSeatMapper.selectForUpdate(sessionId, seatIds); if (rows.size() != seatIds.size()) { throw new BizException("部分座位不存在"); } // 2. 逐个校验状态, 0 表示可售 for (SessionSeat row : rows) { if (row.getStatus() != 0) { throw new BizException("座位已售出, 请刷新后重选"); } } // 3. 锁定座位: 状态改为 2, 让其他请求读不到可售 sessionSeatMapper.lockSeats(sessionId, seatIds, 2); // 4. 生成订单号, 插入订单主表, 状态 0 表示待支付 Order order = Order.create(userId, sessionId, calculateAmount(rows)); orderMapper.insert(order); // 5. 写订单座位关联表, 唯一索引兜底极端并发 orderSeatMapper.batchInsert(order.getId(), sessionId, seatIds); return order.getOrderNo(); }

参数说明:@Transactional 保证第 2 到第 5 步要么全部成功要么全部回滚;selectForUpdate 对应的 SQL 是 SELECT * FROM session_seat WHERE session_id=? AND seat_id IN (?) FOR UPDATE,事务提交前这些行会被锁住,第二个请求只能等待;lockSeats 执行 UPDATE session_seat SET status=2 WHERE session_id=? AND seat_id IN (?) AND status=0,如果受影响行数小于传入座位数,说明有座位已被别人抢先。最后一道保险是 order_seat 表上的唯一索引 uk_session_seat(session_id, seat_id),万一上面两层都漏了,重复插入会抛 DuplicateKeyException,事务回滚。

这三层缺一不可。只靠唯一索引,并发时用户会收到一个看不懂的数据库报错;只靠行锁,如果代码逻辑里有 bug,照样产生脏数据。另外注意锁的粒度:只锁本次要买的几个座位行,不要锁整张表,否则一个热门场次的抢座会堵死其他场次的查询。

4.3 支付回调、出票与超时释放:模拟支付也要讲状态流转

真实微信支付流程是:小程序端调 wx.requestPayment 拉起收银台,用户付款后微信后台请求你配置的回调地址,回调里验签、改订单状态、更新座位。它要求回调地址必须是公网可访问的 HTTPS 接口,很多学生在本地开发时根本收不到回调,于是卡在这一步。

可靠且常见的做法是模拟支付:前端点“确认支付”直接调后端的模拟支付接口,后端收到请求后走与真实回调完全相同的处理逻辑——订单从 0 改 1,同一事务把 session_seat 从 2 改 1。这样做的好处是代码结构里保留了真实回调的入口位置,演示时不依赖商户号也能完整跑通全流程。注意两点:模拟支付接口要做“重复支付校验”,订单状态不是 0 时直接拒绝,防止同一订单被刷两次;超时未支付的订单必须释放座位。

// 定时任务: 每 5 分钟扫描超时未支付订单并释放对应座位 @Scheduled(fixedRate = 300000) @Transactional(rollbackFor = Exception.class) public void releaseExpiredOrders() { List<Order> expired = orderMapper.selectTimeoutOrders(15); // 15 分钟未支付 for (Order order : expired) { orderMapper.updateStatus(order.getId(), 3); // 订单改为已取消 sessionSeatMapper.releaseByOrder(order.getId()); // 对应座位状态改回 0 } }

fixedRate=300000 表示每 5 分钟执行一次,单位是毫秒。超时时间 15 分钟属于业务参数,应该抽到常量类或配置中心,不要写死在 SQL 里。releaseByOrder 要根据订单号查出该订单关联的 seatIds 再批量更新,避免误释放其他订单的座位。这个定时任务如果漏掉,就会出现“用户不付款、座位却一直锁着”的运营事故,属于买家投诉最高发的问题之一。

5. 避坑指南:从开发到演示最容易踩的 5 个坑

以下五条是我和周围开发者在这类项目上反复踩过的,按出现频率排序。每条都按现象、原因、解决的顺序写,照着排查能省下大量时间。

5.1 模拟器正常、真机白屏:域名校验和 127.0.0.1 的锅

现象:开发者工具里电影列表、海报全部正常,点“真机预览”后页面空白或请求一直转圈。

原因有两层:真机上 127.0.0.1 指向手机自己,根本连不到你的电脑;同时小程序平台要求正式请求必须是合法 HTTPS 域名,开发期的不校验域名设置只在开发者工具里生效,真机不认。

解决:开发调试阶段把 BASE_URL 改成电脑的局域网 IP,比如 http://192.168.1.5:8080,并在本地设置里勾选“不校验合法域名”。做完这两步,真机在同一 WiFi 下就能访问。要做正式演示或上线,就得把后端部署到有公网 HTTPS 的服务器,再把域名配到小程序后台的 request 合法域名列表里。

5.2 两个人同时下单同一座位,两个订单都成功

现象:双人同时抢最后一个座位,数据库里出现两条状态为 0 的订单,座位最终卖超。

原因:下单接口没有开事务,也没有行锁和唯一索引。先查询后插入,两个请求都读到 status=0,中间存在空窗期,于是都通过了校验。

解决:按 4.2 的三层方案改造:事务加上 SELECT…FOR UPDATE 行锁,配合 order_seat 唯一索引。改完后再用第 6 章的 ab 并发命令重放一遍,确认同一座位最多只有一条未取消订单。

5.3 场次时间少了 8 小时

现象:管理端排片填 18:00,小程序里显示 10:00,或者反过来差 8 小时。

原因:JDBC 连接串没配置 serverTimezone,MySQL 会话时区默认是 UTC,驱动在转换 TIMESTAMP 时把时间减了 8 小时。这是 MySQL 驱动和时区的经典问题。

解决:连接串加上 serverTimezone=Asia/Shanghai,MySQL 侧执行 SET time_zone = '+08:00';,建表时时间字段优先用 DATETIME 而不是 TIMESTAMP。改完记得重启后端再验证。

5.4 海报裂图:本地路径和上传目录的连锁问题

现象:海报图片时好时坏,数据库里存的是 /uploads/1.jpg,前端拼上 baseUrl 后部分能显示,部分 404。

原因:图片上传到了后端运行目录下的 uploads 子目录,后端重启或重新打包后文件被清空;或者图片地址写死了 localhost,真机上访问不到。

解决:把 file.upload-dir 配置成独立绝对目录,比如 D:/cinema-upload,前端统一用 baseUrl 加相对路径拼接完整 URL。部署上线后建议改用对象存储,数据库只存相对路径,图片和代码彻底分离。

5.5 文档和源码对不上,照着文档走直接卡死

现象:文档说改 application.properties,源码里只有 application.yml;文档说某表有 status 字段,SQL 里根本没有。

原因:这种带万字文档的模板通常迭代过很多版本,文档生成时间和代码打包时间不同步;有时下载目录混乱,把不同版本混淆在一起。

解决:以源码和 SQL 文件为准,文档只当参考。先按第 3 章的最小步骤把主链路跑通,再回头核对文档里提到的扩展功能。跑通前不要花时间逐字精读文档,否则你会在一个已经不存在的文件上浪费一下午。

6. 从能跑到能演示:上线前必须做的一次完整验证

准备一套干净的演示数据:一部电影、一个影厅、三个场次,其中一个场次把部分座位预置成已售。然后按下面的清单完整过一遍,任何一项不达标都先别拿去演示。

模块验证点预期结果
登录小程序授权登录user 表新增记录,openid 唯一
电影列表下拉刷新、海报加载列表完整,裂图 0 张
选座已售座位置灰已售不可点,可选座位可选中
下单提交订单订单状态 0,座位状态变 2
支付模拟支付订单状态变 1,座位状态变 1
超时释放不付款等待 16 分钟订单取消,座位回到可售
退票已支付订单退票订单状态 4,座位释放
管理端上架电影、排片小程序端立即能看到新场次

功能清单过完,再做一次并发冒烟,重点打下单接口:

ab -n 50 -c 10 -p order.json -T application/json http://127.0.0.1:8080/api/order/create

参数说明:-n 50 是总请求数,-c 10 是并发数,order.json 是下单请求体文件,-T 指定 Content-Type。观察两个结果:ab 报告里的 failed 数量应为 0;同时开一个 MySQL 窗口,确认同一个座位最多只有一条未取消订单。第一次跑并发大概率会暴露 5.2 的问题,这恰恰是这一步的意义。

最后说一个我的习惯:正式演示前,重新导入一次 SQL 把数据重置干净,删掉所有测试订单;真机预览用手机流量而不是现场 WiFi,因为现场 AP 的设备隔离经常导致手机连不上电脑。再有就是每个网络请求都配上 loading 提示,响应慢也不至于让页面看起来像死掉。这套系统最值钱的不是那几个页面,而是事务、锁、状态机这些你讲得清楚、也经得起追问的部分。把它吃透,答辩和面试都能拿来当谈资。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 5:40:06

YOLOv5云服务器GPU部署避坑指南:从环境搭建到稳定上线

“模型在本地能跑&#xff0c;换到云服务器就各种崩”&#xff0c;这大概是做目标检测部署时最常听见的一句话。我前段时间刚好把一套YOLOv5模型完整迁移到某云平台的GPU实例上&#xff0c;踩遍了环境编译、权重传输、显存溢出这些坑。这篇内容把整个部署过程拆开讲清楚&#x…

作者头像 李华
网站建设 2026/10/22 5:38:03

梯度下降实战解析:学习率、批量与优化器调参避坑指南

梯度下降这四个字&#xff0c;在机器学习领域几乎天天见。刷课程、读博客&#xff0c;公式都能背下来&#xff0c;但真正动手调参时&#xff0c;loss 曲线不降反升、反复震荡、卡在平台期&#xff0c;这些情况碰到过一遍才知道理论离实践有多远。最近我把那门经典的机器学习公开…

作者头像 李华
网站建设 2026/10/22 5:37:58

K8S监控离线部署:Prometheus/Grafana/Alertmanager镜像合集实战

简介&#xff1a;面向Kubernetes集群运维与监控人员的K8S集群监控资源镜像合集&#xff0c;汇总Prometheus监控体系所需的镜像清单与离线镜像包&#xff0c;适用于离线部署、内网受限环境下的监控搭建。资源共124个文件&#xff0c;其中57个YAML/yml资源清单用于定义部署与Serv…

作者头像 李华
网站建设 2026/10/22 5:36:54

内网K8s主机监控:node-exporter与Prometheus部署实战

简介&#xff1a;面向Kubernetes集群运维与监控工程师&#xff0c;这份资源聚焦node-exporter的部署与告警落地&#xff0c;解决K8s节点CPU、内存、磁盘、网络等主机层指标采集困难、部署步骤分散的问题。资源内含完整部署清单&#xff0c;包括服务、配置、部署、存储声明等5个…

作者头像 李华
网站建设 2026/10/22 5:36:37

AGENTS.md:为AI编程助手建立项目记忆,告别无状态协作

1. 为什么我决定告别“无状态”的AI编程方式1.1 一个让人抓狂的失忆现场半年前我对AI编程助手的态度是又爱又恨。爱是因为它的代码生成能力确实强&#xff0c;恨是因为它太容易“失忆”了。同一个项目我连续写了三个月&#xff0c;但每次新开一个对话窗口&#xff0c;它都要重新…

作者头像 李华
网站建设 2026/10/22 5:36:18

除自身以外数组的乘积:前后缀分解与O(1)空间优化

1. 题目理解与核心考点1.1 题面拆解&#xff1a;这题到底在考什么“238. 除了自身以外数组的乘积”这道题&#xff0c;我刷了不下三遍&#xff0c;每次面试前翻Hot 100还是会重新瞄一眼。原因很简单&#xff1a;它长得太像一道“暴力题”了&#xff0c;但真正动手写的时候&…

作者头像 李华