ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

在 Go 中使用 SQLite 数据库:基于 database/sql 标准接口实现增删改查

在 Go 中使用 SQLite 数据库:基于 database/sql 标准接口实现增删改查 文档教程【免费下载链接】build-web-application-with-golangA golang ebook intro how to build a web with golang项目地址https://gitcode.com/gh_mirrors/bu/build-web-application-with-golang点击查看免费下载导读本文围绕 《Build Web Application with Golang》 第 5.3 节展开讲解如何借助 SQLite 嵌入式关系数据库与 Go 的database/sql标准接口完成建表、连接以及增删改查CRUD全流程。你将掌握为什么 SQLite 适合作为 Go Web 应用的嵌入式存储、如何选择支持database/sql的第三方驱动、如何用参数化占位符安全地执行 SQL以及如何将本节的代码无缝迁移到 MySQL、PostgreSQL 等其他数据库。全文以原文档为骨架并结合仓库内 ch.5.3 示例代码与建表脚本 schema.sql 深入展开。SQLite零配置的嵌入式关系数据库SQLite 是一个开源的嵌入式关系数据库引擎其设计目标决定了它与传统客户端/服务器数据库如 MySQL、PostgreSQL截然不同它实现自包容self-contained、零配置zero-configuration、支持事务transactional并且高度便携、结构紧凑、高效可靠。所谓嵌入式指的是 SQLite 不是一个独立运行的数据库服务进程而是以库的形式嵌入到应用程序内部。使用它的成本极低——在大多数情况下只要确保 SQLite 的二进制文件存在即可开始创建、连接和使用数据库不需要安装服务、配置端口、管理账户权限。仓库中 ch.5.3 的 readme 给出的第一步就是Download and install sqlite 3可见它的安装门槛就是如此简单。正是因为这种文件即数据库的特性SQLite 常被称为开源的 Access它适合单机应用、原型验证、嵌入式设备以及 Web 应用的轻量级数据存储场景。如果你正在寻找一个嵌入式数据库项目或解决方案SQLite 是绝对值得考虑的选项。驱动选型只有支持 database/sql 接口的驱动值得优先考虑三种常见驱动对比Go 官方并未提供数据库驱动而是通过database/sql标准接口来统一操作方式详见 5.1 节 database/sql 接口。Go 支持 SQLite 的驱动比较多但很多并不支持database/sql接口常见的三个驱动对比如下驱动是否支持 database/sql实现方式评价github.com/mattn/go-sqlite3支持基于 cgo目前唯一支持database/sql的 SQLite 驱动也是本书采用的驱动github.com/feyeleanor/gosqlite3不支持基于 cgo自定义接口无法直接与标准库配合github.com/phf/go-sqlite3不支持基于 cgo自定义接口无法直接与标准库配合说明以上三个驱动的实现均基于 cgoGo 调用 C 代码的机制。关于 cgo 的知识可参考 Go 官方文档或本书后续章节。目前支持database/sql接口的 SQLite 驱动只有第一个mattn/go-sqlite3。采用标准接口开发项目有两个显著好处代码与底层驱动解耦业务代码只依赖database/sql的 API不依赖任何驱动特有的接口便于未来迁移以后如果出现更好的驱动只需更换 import 的驱动包以及连接串业务逻辑一行都不用改。这一点在第 5.2 节使用 MySQL 的例子上得到了印证对比 5.2 节 MySQL 示例 与本节的 SQLite 示例会发现两者代码几乎一模一样唯一区别就是导入的驱动包不同以及sql.Open打开数据库的方式不同。这正是database/sql标准接口设计价值的直观体现。驱动是如何注册的database/sql本身不包含任何驱动驱动通过包级init()函数调用sql.Register(name string, driver driver.Driver)完成注册注册信息保存在database/sql内部的一个 map 中drivers[name] driver。在 5.1 节 中可以看到 mattn/go-sqlite3 驱动的注册方式// https://github.com/mattn/go-sqlite3 驱动 func init() { sql.Register(sqlite3, SQLiteDriver{}) }因此在使用时通过空导入_ github.com/mattn/go-sqlite3引入驱动包触发其init()函数自动完成注册之后即可用sql.Open(sqlite3, ...)打开数据库。_前缀表示只执行包的初始化副作用导入而不直接引用包中定义的其他资源这是 Go 语言中注册类驱动包的惯用写法。建表两张表的 SQLite 表结构在编写 Go 代码之前需要先准备好数据库与表。本书从 5.2 节 开始统一采用同一个表结构数据库foo、用户表userinfo及关联的用户信息表userdetail。SQLite 版本对应的建表 SQL 如下同时收录于仓库的 schema.sqlCREATE TABLE userinfo ( uid INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(64) NULL, department VARCHAR(64) NULL, created DATE NULL ); CREATE TABLE userdetail ( uid INT(10) NULL, intro TEXT NULL, profile TEXT NULL, PRIMARY KEY (uid) );与 MySQL 版本见 5.2 节相比可以注意到一个关键差异SQLite 中的自增主键写法为INTEGER PRIMARY KEY AUTOINCREMENT。在 SQLite 中只有整型主键列才具备插入时自动生成的行为而userdetail表中的PRIMARY KEY (uid)属于表级约束并不会自动生成值——它主要用于与userinfo.uid建立关联。用命令行创建数据库并导入表结构仓库中 ch.5.3 的 readme 给出了完整的环境准备步骤与本节示例完全配套下载并安装 sqlite3创建数据库文件运行sqlite3 foo.db生成名为foo的数据库文件注意SQLite 的数据库就是一个普通文件foo.db即出现在当前目录导入表结构在 sqlite3 交互提示符中执行sqlite .read schema.sql验证表是否创建成功sqlite .tables userinfo退出 sqlitesqlite .exit获取驱动依赖运行go get下载并安装远端包即github.com/mattn/go-sqlite3运行程序go run main.go。示例代码基于 database/sql 的完整增删改查下面看 Go 程序如何通过database/sql标准接口操作数据库表数据完成增删改查全流程。代码与仓库中的 ch.5.3 示例一致package main import ( database/sql fmt time _ github.com/mattn/go-sqlite3 ) func main() { db, err : sql.Open(sqlite3, ./foo.db) checkErr(err) //插入数据 stmt, err : db.Prepare(INSERT INTO userinfo(username, department, created) values(?,?,?)) checkErr(err) res, err : stmt.Exec(astaxie, 研发部门, 2012-12-09) checkErr(err) id, err : res.LastInsertId() checkErr(err) fmt.Println(id) //更新数据 stmt, err db.Prepare(update userinfo set username? where uid?) checkErr(err) res, err stmt.Exec(astaxieupdate, id) checkErr(err) affect, err : res.RowsAffected() checkErr(err) fmt.Println(affect) //查询数据 rows, err : db.Query(SELECT * FROM userinfo) checkErr(err) for rows.Next() { var uid int var username string var department string var created time.Time err rows.Scan(uid, username, department, created) checkErr(err) fmt.Println(uid) fmt.Println(username) fmt.Println(department) fmt.Println(created) } //删除数据 stmt, err db.Prepare(delete from userinfo where uid?) checkErr(err) res, err stmt.Exec(id) checkErr(err) affect, err res.RowsAffected() checkErr(err) fmt.Println(affect) db.Close() } func checkErr(err error) { if err ! nil { panic(err) } }可以看出这段代码与 5.2 节 MySQL 示例 中的代码几乎一模一样唯一改变的就是导入的驱动换了然后调用sql.Open时采用了 SQLite 的方式驱动名sqlite3 数据库文件路径./foo.db。这正是database/sql标准接口一次编写、多库迁移价值的直接体现。关键 API 详解sql.Open、Prepare、Exec、Query、Scan结合 5.1 节对 database/sql 接口的剖析 与本节示例梳理一下核心调用链中每个 API 的职责与底层原理sql.Open(driverName, dataSourceName)打开一个注册过的数据库驱动。第二个参数是 DSNData Source Name。在 SQLite 场景下DSN 就是数据库文件的路径如./foo.db。注意sql.Open只是建立连接配置、校验驱动注册真正的连接在首次执行 SQL 时才会建立。db.Prepare(query)返回一个准备好执行 SQL 的准备语句Stmt。底层对应driver.Stmt驱动的Prepare会先在数据库端解析并编译 SQL后续多次Exec可复用该准备状态提升重复执行效率。stmt.Exec(args...)执行准备语句中的 SQL。用于 INSERT、UPDATE、DELETE 等写操作返回Result。Result接口包含两个方法LastInsertId()返回插入操作得到的自增 IDRowsAffected()返回受影响的行数详见 5.1 节 driver.Result。db.Query(sql, args...)直接执行查询语句并返回Rows结果集用于 SELECT 操作。rows.Next()rows.Scan(dest...)迭代结果集每次把当前行的各列依次扫描到对应的变量地址中。Scan的目标类型需与列数据类型匹配——在本例中created列被扫描进time.Time变量。db.Close()关闭数据库连接。仓库中的示例使用了defer db.Close()来确保函数退出时自动关闭。参数化查询用?占位符防御 SQL 注入在本节示例中所有携带用户数据的 SQL 都使用了?占位符的形式stmt, err : db.Prepare(INSERT INTO userinfo(username, department, created) values(?,?,?)) res, err : stmt.Exec(astaxie, 研发部门, 2012-12-09)与字符串拼接 SQL 相比这种写法有两个关键优势防止 SQL 注入占位符的值由驱动在底层进行转义与绑定而不是直接嵌入 SQL 文本用户输入无法改变 SQL 语句的结构类型清晰、复用高效Prepare一次、Exec多次同一语句可以携带不同参数反复执行。这一点在 5.2 节 中也得到了明确强调我们可以看到我们传入的参数都是?对应的数据这样做的方式可以一定程度上防止 SQL 注入。 这是所有database/sql驱动包括 MySQL、SQLite、PostgreSQL通用的最佳实践。配套管理工具SQLite 也提供了可视化管理工具http://sqliteadmin.orbmu2k.de/SQLite Administrator可以方便地新建数据库并进行管理操作。对于命令行用户SQLite 自带的sqlite3交互程序已足够完成建库、建表、查询与数据导出等日常需求如仓库 readme 中演示的.read schema.sql、.tables、.exit命令。迁移到其他数据库标准接口的威力由于本节代码完全基于database/sql标准接口编写将其迁移到 MySQL 只需要做两处变更对照 5.2 节示例将空导入改为_ github.com/go-sql-driver/mysql将sql.Open的第一个参数改为mysqlDSN 改为 MySQL 的连接串如astaxie:astaxie/test?charsetutf8。其余代码——包括Prepare、Exec、Query、Scan、RowsAffected的调用——全部保持不变。这也正是本节强调采用标准接口有利于以后出现更好的驱动的时候做迁移的实践意义。小结本节的核心结论可以归纳为三点SQLite 是零配置的嵌入式数据库无需独立服务进程安装二进制即可建库使用适合轻量级、嵌入式场景驱动选择要认准database/sql标准接口目前唯一支持该接口的 SQLite 驱动是 mattn/go-sqlite3通过空导入_ github.com/mattn/go-sqlite3注册后即可使用标准接口带来零成本迁移基于database/sql的增删改查代码在不同数据库间几乎可以原样复用配合?占位符还能天然防御 SQL 注入。配套的完整可运行示例、建表脚本与环境准备步骤可分别参考仓库中的 ch.5.3/main.go、ch.5.3/schema.sql 与 ch.5.3/readme.md。更深入的database/sql接口原理驱动注册、连接池、各接口定义请参阅 5.1 节 database/sql 接口后续还可继续学习 5.4 节使用 PostgreSQL 数据库。赞分享文档教程【免费下载链接】build-web-application-with-golangA golang ebook intro how to build a web with golang项目地址https://gitcode.com/gh_mirrors/bu/build-web-application-with-golang点击查看免费下载相关推荐用 Go 连接 MySQL基于 database/sql 驱动的完整增删改查实战指南用 Go 连接 MySQL基于 database/sql 驱动的完整增删改查实战指南 MySQL 凭借开源、易用、稳定等特点长期是 LAMP 架构中 Web文档教程TIL 实战在 Go 中用 database/sql 与 go-sqlite3 连接 SQLite 数据库TIL 实战在 Go 中用 database/sql 与 go sqlite3 连接 SQLite 数据库 本篇技术指南以 TIL 仓库中的 connect文档教程知识库用 Go 操作 MySQL基于 database/sql 接口的增删改查实战Build Web Application with Golang 第 5.2 章用 Go 操作 MySQL基于 database/sql 接口的增删改查实战Build Web Application with Golang 第 5.2文档教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表