- 文档
- 教程
【免费下载链接】build-web-application-with-golang
A golang ebook intro how to build a web with golang
导读
本文围绕开源 Go 电子书《build-web-application-with-golang》第 5.5 章配套示例(ch.5.5)展开,完整讲解如何在本仓库环境中搭建 SQLite3 数据库、初始化 beedb ORM,并依次走通基于结构体与 map 的增删改查(CRUD)、Join联表查询与GroupBy/Having分组查询。读完本文,你将能够复现ch.5.5示例的全部运行流程,并掌握 beedb 链式查询 API 的核心用法与底层映射原理。
一、示例概览:ch.5.5 要解决什么问题
第 5.5 章的目标是演示如何使用 Go 编写的轻量级 ORM 框架beedb对 SQLite3 数据库执行基础 CRUD 操作。仓库中的配套代码位于 fa/code/src/apps/ch.5.5/(英文版同目录见 en/code/src/apps/ch.5.5/),共包含三个文件:
| 文件 | 作用 |
|---|---|
| readme.md | 运行环境搭建与启动步骤说明 |
| schema.sql | 建表脚本,创建userinfo与userdetail两张表 |
| main.go | 完整示例程序,覆盖插入、查询、更新、删除、联表与分组查询 |
主程序的注释明确说明了用途:"Example code for Chapter 5.5, Purpose is to show to use BeeDB ORM for basic CRUD operations for sqlite3",即本示例是全书 beedb 章节(对应英文正文 en/05.5.md)的可运行落地版本。
二、环境准备:安装 SQLite3 并创建数据库
按照 readme.md 中的步骤,首先需要下载并安装 SQLite3(各主流 Linux 发行版均可通过系统包管理器安装,macOS 与 Windows 可前往官方站点下载二进制)。
安装完成后,在工作目录下执行以下命令创建名为foo的数据库文件:
sqlite3 foo.dbsqlite3命令在指定一个不存在的.db文件时会自动创建该数据库文件。注意main.go中定义了常量DB_PATH = "./foo.db"(见 main.go),因此数据库文件应创建在与main.go相同的目录下,程序运行时才能正确打开。
三、加载 schema.sql 建表并验证
3.1 建表脚本详解
进入 sqlite3 交互式终端后,通过.read命令读取建表脚本:
sqlite> .read schema.sqlschema.sql 的内容定义了两张表:
- userinfo:用户信息主表,
uid为INTEGER PRIMARY KEY AUTOINCREMENT自增主键,包含username、department(部门)、created(创建时间)三个业务字段; - userdetail:用户详情表,
uid为INT(10)主键,包含intro(简介)与profile(档案)两个 TEXT 字段。
这两张表之间的关联正是后续joinTables函数中userinfo.uid=userdetail.uid联表条件的基础。
3.2 验证表是否创建成功
加载脚本后,用.tables命令列出当前数据库中的所有表:
sqlite> .tables userinfo userdetail输出中出现userinfo与userdetail即表示建表成功。完成验证后退出交互式终端:
sqlite> .exit四、拉取依赖并初始化 beedb
4.1 使用 go get 安装依赖
readme.md 第 5 步要求运行go get下载并安装远程包。main.go的 import 块(main.go)声明了三个依赖:
import ( "database/sql" "github.com/astaxie/beedb" _ "github.com/mattn/go-sqlite3" "time" )其中github.com/astaxie/beedb为 ORM 框架本体,github.com/mattn/go-sqlite3为 SQLite3 驱动(以匿名导入方式注册,仅触发其init()完成驱动注册)。安装命令为:
go get github.com/astaxie/beedb go get github.com/mattn/go-sqlite34.2 建立数据库连接与 ORM 对象
main.go的入口函数展示了 beedb 的初始化方式(main.go):
db, err := sql.Open("sqlite3", DB_PATH) checkError(err) orm = beedb.New(db)流程分为两步:先用database/sql标准接口打开 SQLite3 连接,再通过beedb.New(db)将连接封装为beedb.Model类型的 ORM 对象。由于 beedb 基于database/sql标准接口实现,任何实现了该接口的驱动都可以接入——正文 en/05.5.md 中列出了作者测试过的 MySQL、PostgreSQL、SQLite、Oracle、ODBC 等驱动。对于 MySQL/SQLite,beedb.New的第二个参数(数据库引擎标识)可以省略;若是 SQLServer 需要传"mssql",PostgreSQL 则传"pg"。
4.3 结构体与表的映射规则
示例定义了与userinfo表对应的结构体(main.go):
type Userinfo struct { Uid int `beedb:"PK"` Username string Department string Created string }这里有两个关键点:
- 主键标记:beedb 默认以字段
id作为主键;当主键字段名不同(如这里的Uid)时,必须通过 tag 显式声明,写作`beedb:"PK"`(正文 en/05.5.md 中的写法为`PK`,功能一致)。 - 驼峰命名自动转换:beedb 会自动将结构体及字段的驼峰命名转换为数据库中的小写下划线命名,例如结构体
Userinfo对应表userinfo,字段Username对应列username。这也是示例中结构体字段名与表列名可以"同名异构"的原因。
此外,beedb 支持调试模式,在初始化后设置beedb.OnDebug = true即可打印底层执行的 SQL 语句,方便排查问题(见 en/05.5.md)。
五、核心 CRUD 源码走读
5.1 插入:结构体方式与 map 方式
结构体方式通过orm.Save(&obj)完成。insertUsingStruct(main.go)填充Username、Department与Created(时间由getTimeStamp()按"2006-01-02 15:04:05"格式生成)后调用Save,插入成功后结构体的Uid会被回填为自增 ID,函数将其作为返回值供后续查询使用。
map 方式通过链式调用实现。insertUsingMap(main.go)构建map[string]interface{},键为列名,值为数据:
add := make(map[string]interface{}) add["username"] = "astaxie" add["department"] = "cloud develop" add["created"] = getTimeStamp() id, err := orm.SetTable("userinfo").Insert(add)SetTable("userinfo")指明操作的表,Insert返回最后插入的行 ID。这种链式调用风格与 jQuery 类似——每个方法返回 ORM 对象本身,便于继续拼接后续操作(见 en/05.5.md)。正文还补充了批量插入方式:构建[]map[string]interface{}切片后调用InsertBatch(addslice)即可一次插入多条记录。
5.2 查询:单条、多条与 map 结果
getOneUserInfo(main.go)展示了带条件查询单条记录:
orm.Where("uid=?", id).Find(&obj)Where支持多种写法(详见 en/05.5.md):
- 两个参数:
orm.Where("uid=?", 27),?为占位符,避免 SQL 注入; - 单参数且为整数:
orm.Where(3)是Where("主键=?", 3)的简写; - 多条件:
orm.Where("name = ? and age < ?", "john", 88)。
getAllUserInfo(main.go)演示了分页查询多条记录:
orm.Limit(10).Where("uid>?", id).FindAll(&alluser)Limit(10)表示最多返回 10 条,起始位置默认为 0;Limit(10, 20)则从第 20 条开始取 10 条。结果直接映射到[]Userinfo切片。若需要排序,可链式追加OrderBy("uid desc,username asc")。
getMapsFromSelect(main.go)展示了将查询结果放入 map 的方式:
orm.SetTable("userinfo").SetPK("uid").Where(id).Select("uid,username").FindMap()SetPK("uid")显式指定主键列(map 方式下默认主键为id,此处必须声明);Select("uid,username")指定要返回的列,不指定则返回全部列;FindMap()返回[]map[string][]byte类型,数值型字段需要自行转换。
5.3 更新:Save 与 map 更新
updateUserinfo(main.go)体现了 beedb 的"主键即更新依据"设计:重新填充Uid及字段后再次调用orm.Save(&obj),beedb 检测到结构体已携带主键值,便执行 UPDATE 而非 INSERT(正文 en/05.5.md 对此有明确说明)。
updateUsingMap(main.go)则演示了 map 批量更新:
t := make(map[string]interface{}) t["username"] = "updateastaxie" lastId, err := orm.SetTable("userinfo").Where("uid>?", id).Update(t)被注释掉的orm.SetTable("userinfo").SetPK("uid").Where(2).Update(t)是单条更新写法——Where接收整数 2 时等价于Where("uid=?", 2);而示例采用的Where("uid>?", id)会将所有满足条件的记录一并更新,属于批量更新。
5.4 删除:Delete、DeleteAll 与 DeleteRow
示例提供了三种删除方式(main.go):
deleteWithUserinfo:先按主键查出一条记录,再调用orm.Delete(&obj)删除单条;deleteRows:使用原生 SQL 风格的链式删除,orm.SetTable("userinfo").Where("uid>?", 2).DeleteRow()删除满足条件的所有记录;deleteAllUserinfo:先FindAll查出切片,再调用orm.DeleteAll(&alluser)批量删除。
对应正文 en/05.5.md 的三种删除示例,覆盖了"按对象删、按切片删、按条件删"三种常见场景。
六、进阶:联表查询与 Group By / Having
6.1 Join 联表查询
beedb 不直接支持结构体之间的关联映射,但通过SetTable链式 API 提供了 SQL 风格的联表能力。joinTables(main.go)实现了一个 LEFT JOIN:
orm.SetTable("userinfo"). Join("LEFT", "userdetail", "userinfo.uid=userdetail.uid"). Where("userinfo.uid=?", id). Select("userinfo.uid,userinfo.username,userdetail.profile"). FindMap()Join方法接收三个参数(en/05.5.md):
| 参数位置 | 含义 | 示例取值 |
|---|---|---|
| 第一个 | 连接类型 | INNER、LEFT、OUTER、CROSS等 |
| 第二个 | 关联的表名 | userdetail |
| 第三个 | 连接条件 | userinfo.uid=userdetail.uid |
联表结果通过FindMap以 map 形式返回,可同时取两张表的列(如userdetail.profile)。
6.2 Group By 与 Having
groupby(main.go)演示了分组统计查询:
orm.SetTable("userinfo").GroupBy("username").Having("username='updateastaxie'").FindMap()GroupBy("username")指定分组字段;Having(...)指定分组后的过滤条件,语义与 SQL 标准一致。
对应正文 en/05.5.md 的说明,二者组合可完成"先分组、再按组过滤"的聚合查询需求。
七、运行验证与预期输出
完成上述步骤后,在ch.5.5目录下执行第 6 步:
go run main.go程序将按照main函数的编排顺序(main.go)依次执行:插入(结构体 + map)→ 单条/多条查询 → 更新(结构体 + map)→ map 查询 / 分组 / 联表 → 三种方式删除。每个函数开头都会打印函数名,例如:
Inserting insertUsingStruct() {0 Test Add User Test Add Department 2026-10-03 00:43:26} insertUsingMap() Last row inserted id = 2 ...insertUsingStruct()打印的结构体中Uid:0为插入前的初始值,插入后通过返回值拿到自增主键。若在初始化后启用了beedb.OnDebug = true,终端还会输出每条操作对应的真实 SQL 语句,便于将链式 API 与底层 SQL 一一对应。
八、注意事项与扩展阅读
- 驱动适配:beedb 支持
database/sql标准接口,除 SQLite3 外,正文 en/05.5.md 还测试了 MySQL、PostgreSQL、Oracle、ODBC 等驱动;切换数据库时只需更换匿名导入的驱动包,并在beedb.New中按需传入引擎标识。 - 命名转换:beedb 将驼峰命名自动转为小写下划线,因此自定义结构体时字段名需与表列名保持这种对应关系,否则需自行处理映射。
- 主键声明:凡是主键字段不是
id的表(如本示例的uid),在结构体 tag 与 map 查询中都必须通过PKtag /SetPK显式声明。 - 关联查询边界:beedb 不支持结构体间的一对一、一对多、多对多自动关联(正文 en/05.5.md 指出其设计定位是轻量 ORM),需要联表时使用
Join链式调用;正文末尾的 "Future" 一节记录了作者计划支持关联映射、自动建表、goroutine 连接池等后续方向。 - 章节关联:本示例是全书第 5 章"数据库操作"中 SQLite 小节(5.2~5.4 分别讲解了
database/sql与 SQLite/MySQL/PostgreSQL 驱动用法)之后的 ORM 实践环节,后续章节(05.6)将继续介绍 NoSQL 数据库。
- 文档
- 教程
【免费下载链接】build-web-application-with-golang
A golang ebook intro how to build a web with golang
相关推荐
build-web-application-with-golang 第 5.5 章实战:基于 beedb 的 SQLite3 环境搭建与 CRUD 示例运行指南
build web application with golang 第 5.5 章实战:基于 beedb 的 SQLite3 环境搭建与 CRUD 示例运行指南
文档教程基于 beedb 开发 Go 轻量级 ORM:struct 映射与 CRUD 全流程实战(build-web-application-with-golang 第 5.5 节)
基于 beedb 开发 Go 轻量级 ORM:struct 映射与 CRUD 全流程实战(build web application with golang 第
文档教程build-web-application-with-golang ORM教程:基于beedb开发数据访问层
build web application with golang ORM教程:基于beedb开发数据访问层 你是否还在为Golang Web开发中的数据访问层
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考