用 SQLite + net/http 实现轻量餐馆菜单系统:全局复用 *sql.DB,建表含 UNIQUE(name,category),提供5个 REST 接口,前端用 HTML+Fetch,部署注意文件路径权限与 busy_timeout。

直接用 Go 实现一个能跑起来的餐馆菜单管理系统,核心不是堆框架,而是选对数据存储方式和 HTTP 交互边界——SQLite + net/http 足够支撑中小餐馆的增删改查、分类展示和基础搜索,没必要一上来就上 PostgreSQL 或 Gin。
用 database/sql + sqlite3 做轻量持久化
Go 标准库的 database/sql 足够应付菜单这类结构稳定、读多写少的数据。关键在驱动选择和连接管理:
- 用
mattn/go-sqlite3驱动,编译时需安装 C 工具链(gcc),Windows 用户注意装 TDM-GCC 或 MSYS2 - 避免每次请求都
sql.Open(),全局复用一个*sql.DB实例,并调用db.SetMaxOpenConns(10)防止连接耗尽 - 菜单表建议至少包含:
id,name,price,category,is_available(布尔用整数存,SQLite 没原生 bool) - 建表语句里加
UNIQUE(name, category)防止同类别重复菜名,比应用层校验更可靠
用 net/http 暴露 RESTful 接口,不引入 Gin
菜单系统接口简单,5 个端点就够用:GET /menu、GET /menu/:id、POST /menu、PUT /menu/:id、DELETE /menu/:id。用标准库完全可控:
- 路由别手写 if-else 判断 path,用
http.ServeMux或直接http.HandleFunc绑定,清晰不绕 - 接收 JSON 时,用
json.NewDecoder(r.Body).Decode(&v),别用ioutil.ReadAll再json.Unmarshal—— 前者流式解析,内存友好 - 返回错误统一用
http.Error(w, msg, status),比如菜品不存在返回http.StatusNotFound,别混用 200 + 错误字段 - 所有写操作(POST/PUT/DELETE)必须校验
r.Method,防止 GET 请求意外触发修改
前端用纯 HTML + Fetch,不接 Vue/React
餐馆老板可能只用 iPad 查看或更新菜单,页面不需要复杂交互。一个 index.html 加几段 fetch() 就够:
立即学习“go语言免费学习笔记(深入)”;
-
GET /menu渲染为带“编辑”“下架”按钮的表格,每行绑定data-id - 编辑弹窗用原生
prompt()或简单 form,提交前检查price > 0和name非空,前端校验只是体验优化,后端仍要兜底 - 删除用
fetch(url, { method: 'DELETE' }),别用 GET 模拟删除(不安全,易被爬虫误触发) - 所有请求加
headers: { 'Content-Type': 'application/json' },否则 Go 后端json.Decode会静默失败
部署时注意 SQLite 文件路径和权限
本地开发时 ./menu.db 没问题,但部署到 Linux 服务器容易出错:
- 启动程序前确保 db 文件所在目录可写,比如用
chown appuser:appuser /var/www/menu - 不要把 db 放在
/tmp下——重启可能清空;也不放代码目录里——git 会误提交 - 连接字符串用
file:/var/www/menu/menu.db?_busy_timeout=5000,加_busy_timeout防止并发写时返回database is locked - 备份只需定时
cp menu.db menu.db.$(date +%F),SQLite 支持热拷贝,不用停服务
真正卡住进度的往往不是语法,而是 SQLite 的文件锁行为、HTTP 请求头缺失、或前端没处理 4xx 状态码就假死——这些点比选什么 ORM 更影响上线速度。










