深入探究 Go 语言中使用 SQLite 数据库

引言

在软件开发中,数据库是管理和存储数据的关键组件。SQLite 作为一款轻量级的嵌入式数据库,因其零配置、高性能和易于集成等特性,成为众多小型项目和嵌入式系统的理想选择。而 Go 语言以其高效、简洁的特点,为操作 SQLite 数据库提供了强大的支持。本文将结合实际代码,深入介绍如何在 Go 语言中使用 SQLite 数据库,包括数据库和表的创建、增删改查操作以及操作的优化。

环境准备

在开始使用 Go 语言操作 SQLite 数据库之前,我们需要安装必要的库。可以使用以下命令安装github.com/mattn/go-sqlite3库:

go get github.com/mattn/go-sqlite3

创建数据库和表

创建数据库

在 Go 语言中,使用database/sql包结合github.com/mattn/go-sqlite3驱动来操作 SQLite 数据库。通过sql.Open函数可以打开或创建一个 SQLite 数据库文件。以下是一个简单的示例:

package mainimport ("database/sql""fmt""path/filepath"_ "github.com/mattn/go-sqlite3"
)const defDBPath = "./data"func initContDB() error {dbFile := filepath.Join(defDBPath, "test.db")var err errorgDB, err := sql.Open("sqlite3", dbFile)if err != nil {fmt.Println("open test db ", err)return err}fmt.Println("open test db ok")_, err = gDB.Query("SELECT COUNT(*) FROM sqlite_master")if err != nil {fmt.Println("test db query ", err)return err}return nil
}

在上述代码中,sql.Open函数接受两个参数:驱动名(这里是sqlite3)和数据库文件的路径。如果文件不存在,SQLite 会自动创建该文件。

创建表

在创建数据库之后,我们需要创建表来存储数据。可以使用Exec方法执行 SQL 语句来创建表。为了避免重复创建表,我们可以先检查表是否已经存在。以下是创建表的示例代码:

func existTable(db *sql.DB, tbl string) bool {stmt, err := db.Prepare("SELECT COUNT(*) FROM sqlite_master where tbl_name=?")if err != nil {fmt.Println(err)return false}defer stmt.Close()row := stmt.QueryRow(tbl)if row == nil {return false}var val introw.Scan(&val)if val == 0 {return false}return true
}func createTable() {if existTable(gDB, "t_cont_info") {return}tbl := `CREATE TABLE [t_cont_info]([name] VARCHAR PRIMARY KEY NOT NULL UNIQUE, [ver] VARCHAR, [image] VARCHAR NOT NULL, [cmd] INT(2) NOT NULL, [opt_cmd] INT(2) NOT NULL, [cpus] INT(2) NOT NULL, [cpu_threshold] INT(4) NOT NULL, [memory] INT(4) NOT NULL, [mem_threshold] INT(4) NOT NULL, [store_cap] INT(4) NOT NULL, [store_threshold] INT(4) NOT NULL, [ip] VARCHAR, [create_time] VARCHAR, [start_time] VARCHAR, [runtimes] BIGINT, [backup_path] VARCHAR,[opt_time] VARCHAR);`_, err := gDB.Exec(tbl)if err != nil {fmt.Println(err)return}fmt.Println("creatTable t_cont_info")
}

在上述代码中,existTable函数用于检查指定的表是否存在。createTable函数根据检查结果决定是否创建t_cont_info表。

增删改查操作

插入数据

插入数据可以使用PrepareExec方法。以下是插入的示例代码:

func insertWarnMsg(name, msg string) error {stmt, err := gWarnDB.Prepare(`INSERT INTO t_cont_info([name], [msg], [opt_time]) VALUES (?,?,?)`)if err != nil {fmt.Println(err)return err}_, err = stmt.Exec(name, msg, getLocalTime())if err != nil {stmt.Close()fmt.Println(err)return err}stmt.Close()checkWarnLimit(name)return nil
}

在上述代码中,Prepare方法用于准备 SQL 语句,Exec方法用于执行插入操作。

更新数据

更新数据的操作与插入数据类似,同样使用PrepareExec方法。以下是更新的示例代码:

func updContInfo(ct ContItem) {smt, err := gDB.Prepare("SELECT [name] FROM t_cont_info WHERE name=?")if err != nil {fmt.Println(err)return}defer smt.Close()upd := falserow := smt.QueryRow(ct.Name)if row != nil {var name stringerr = row.Scan(&name)if err != nil {} else if name == ct.Name {upd = true}}if upd {sqlCmd := `UPDATE t_cont_info SET [ver]=?, [image]=?, [cmd]=?, [opt_cmd]=?, [cpus]=?, [cpu_threshold]=?, [memory]=?, [mem_threshold]=?, [store_cap]=?, [store_threshold]=?, [ip]=?, [create_time]=?, [start_time]=?, [runtimes]=?, [backup_path]=?, [opt_time]=? WHERE [name]=?`stmt, err := gDB.Prepare(sqlCmd)if err != nil {fmt.Println(err, ", sql: ", sqlCmd)return}defer stmt.Close()_, err = stmt.Exec(ct.Ver, ct.Img, ct.Cmd, ct.OptCmd, ct.CPUs, ct.CPUThreshold,ct.Memory, ct.MemThreshold, ct.StoreCap, ct.StoreThreshold, ct.IP, ct.CreateTime,ct.StartTime, ct.RunTimes, ct.BackupPath, getLocalTime(), ct.Name)if err != nil {fmt.Println(err)return}} else {stmt, err := gDB.Prepare(`INSERT INTO t_cont_info([name] , [ver], [image], [cmd], [opt_cmd], [cpus], [cpu_threshold], [memory], [mem_threshold], [store_cap], [store_threshold], [ip], [create_time], [start_time], [runtimes], [backup_path], [opt_time]) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`)if err != nil {fmt.Println(err)return}defer stmt.Close()_, err = stmt.Exec(ct.Name, ct.Ver, ct.Img, ct.Cmd, ct.OptCmd, ct.CPUs, ct.CPUThreshold,ct.Memory, ct.MemThreshold, ct.StoreCap, ct.StoreThreshold, ct.IP, ct.CreateTime,ct.StartTime, ct.RunTimes, ct.BackupPath, getLocalTime())if err != nil {fmt.Println(err)return}}
}

在上述代码中,首先检查数据是否存在,如果存在则更新数据,否则插入新数据。

删除数据

删除数据可以使用PrepareExec方法执行DELETE语句。以下是删除的示例代码:

func deleteContItem(name string) {del := func(tbl, name string) {stmt, err := gDB.Prepare(fmt.Sprintf("DELETE FROM %s WHERE [name]=?", tbl))if err != nil {fmt.Println(err)return}defer stmt.Close()_, err = stmt.Exec(name)if err != nil {fmt.Println(err)return}}del("t_cont_info", name)del("t_cont_res_map", name)fmt.Println("deleteContItem: ", name)
}

在上述代码中,定义了一个匿名函数del来执行删除操作,分别删除t_cont_infot_cont_res_map表中指定名称的数据。

查询数据

查询数据可以使用Query方法执行SELECT语句,并使用Scan方法将结果扫描到变量中。以下是查询所有数据的示例代码:

func loadFromDB() (lst []ContItem, err error) {rows, err := gDB.Query(`SELECT [name] , [ver], [image], [cmd], [opt_cmd], [cpus], [cpu_threshold], [memory], [mem_threshold], [store_cap], [store_threshold], [ip], [create_time], [start_time], [runtimes], [backup_path] FROM t_cont_info`)if err != nil {fmt.Println(err)return}defer rows.Close()for rows.Next() {var ct ContItemrows.Scan(&ct.Name, &ct.Ver, &ct.Img, &ct.Cmd, &ct.OptCmd, &ct.CPUs, &ct.CPUThreshold,&ct.Memory, &ct.MemThreshold, &ct.StoreCap, &ct.StoreThreshold, &ct.IP,&ct.CreateTime, &ct.StartTime, &ct.RunTimes, &ct.BackupPath)ct.DevMapList, _ = loadContResMap(ct.Name, CONT_RES_DEV)ct.VolMapList, _ = loadContResMap(ct.Name, CONT_RES_VOL)ct.PortMapList, _ = loadContResMap(ct.Name, CONT_RES_PORT)lst = append(lst, ct)fmt.Println("loadFromDB: ", ct)}return
}

在上述代码中,Query方法返回一个Rows对象,通过Next方法遍历结果集,并使用Scan方法将数据存储到ContItem结构体中。

操作优化

批量操作

在进行大量数据的插入或更新操作时,可以使用事务来提高性能。事务可以将多个操作合并为一个原子操作,减少数据库的开销。以下是一个使用事务进行批量插入的示例代码:

func batchInsert(data []interface{}) error {tx, err := gDB.Begin()if err != nil {return err}stmt, err := tx.Prepare("INSERT INTO table_name (column1, column2) VALUES (?,?)")if err != nil {tx.Rollback()return err}defer stmt.Close()for _, item := range data {_, err = stmt.Exec(item.Value1, item.Value2)if err != nil {tx.Rollback()return err}}return tx.Commit()
}

在上述代码中,Begin方法开始一个事务,Prepare方法准备 SQL 语句,Exec方法执行插入操作,最后使用Commit方法提交事务。如果发生错误,使用Rollback方法回滚事务。

索引优化

为经常用于查询条件的列创建索引可以提高查询性能。例如,在t_cont_info表中,如果经常根据name列进行查询,可以为name列创建索引:

func createIndex() {_, err := gDB.Exec("CREATE INDEX idx_name ON t_cont_info (name)")if err != nil {fmt.Println(err)return}fmt.Println("create index idx_name")
}

在上述代码中,使用CREATE INDEX语句为name列创建索引。

总结

本文深入介绍了如何在 Go 语言中使用 SQLite 数据库,包括数据库和表的创建、增删改查操作以及操作的优化。通过使用database/sql包和github.com/mattn/go-sqlite3驱动,我们可以方便地操作 SQLite 数据库。在实际开发中,根据具体需求选择合适的操作方法和优化策略,可以提高程序的性能和稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/84861.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/84861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Portable Computer Power Adapter

Portable Computer Power Adapter 笔记本电源适配器,将220伏特的交流电转化直流电 现在的适配器真的体积之大,让我无法理解,本来便携计算机为了方便减少体积重量,现在都倒反天罡了。让我无法理解设计师是怎么干出来的。这玩意有2…

Uniapp 网络请求封装专题

目录 一、前言 二、uniapp官方文档 三、举例演示 3.1 使用说明 3.2 Content-Type 3.2.1 ​​基本概念 ​​3.2.2 核心作用 3.2.3 常见 Content-Type 类型及使用场景 1)文本类 a)text/plain​​​​ b)text/html​​ 2&#xf…

2025年渗透测试面试题总结-2025年HW(护网面试) 07(题目+回答)

安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 2025年HW(护网面试) 07 一、OWASP Top 10 2023核心漏洞 二、XSS窃取Cookie全流程 三、渗透测试五阶段模型…

Seata分布式事务解决框架

Seata(Simple Extensible Autonomous Transaction Architecture)是一个开源的分布式事务解决方案,旨在帮助开发者更容易地在微服务架构中解决分布式事务问题。 你可以把它理解为一个工具箱,专门用来处理微服务之间操作的一致性。…

旧物回收小程序开发:开启绿色生活新方式

在环保理念日益深入人心的今天,每一件旧物都承载着资源再生的无限可能。我们精心打造的旧物回收小程序,宛如一把神奇的钥匙,为你开启绿色生活新方式! 想象一下,家中堆积如山的旧衣物、闲置的电子产品、废弃的书籍杂志…

STM32 串口通信②:蓝牙模块HC-05控制单片机

一 前言 上一篇我们已经成功实现单片机和电脑的连接,接下来,我们学习一个有趣的板块,HC-05蓝牙模块,这个蓝牙模块,我们就要建立手机和单片机的通讯啦,还是比较有趣的一个过程,大家可以跟着多操作…

【Verilog】Verilator的TestBench该用C++还是SystemC

Verilator的Testbench(测试平台)主要使用 C 或 SystemC 来编写。这是由Verilator的工作原理决定的:它将你的Verilog/SystemVerilog设计转换成一个C类,因此你需要一个C环境来实例化和驱动这个类。 下面详细说明这两种方式以及如何…

71-Oracle Undo与Flashback管理(Guarantee设置)深度解析

小伙伴们有没有在操作undo表空间、Flashback管理,时间保留设置,总有些配置需要提前预置好,否则闪回查询和表的时候出现报错。 需短期恢复(秒级~小时)直接上UNDO_RETENTION同时启用RETENTION GUARANTEE,Und…

单片机——浮点数转换4位数码管显示

浮点数转换4位数码管显示 static char buffer[5]; int DecimalPlace 0; #define HideChar h void DisplayFloatOn4LED(float value) {long integer roundf(value );if (integer > 9999) //4位{integer 9999;snprintf(buffer, sizeof(buffer), "%4ld", integer…

金融行业B端系统布局实战:风险管控与数据可视化的定制方案

摘要 在金融行业,一次小小的数据泄露可能引发千万级资金损失,一次错误的风险评估或许让企业陷入危机。传统 B 端系统布局在应对复杂多变的金融业务时,常出现风险预警滞后、数据杂乱无章的情况,让从业者如履薄冰。如何才能在瞬息万…

融合LSTM与自注意力机制的多步光伏功率预测新模型解析

这篇论文《Improved multistep ahead photovoltaic power prediction model based on LSTM and self-attention with weather forecast data》(2024, Applied Energy)聚焦在 多步光伏功率预测 中,如何结合 LSTM 与自注意力机制(se…

Blazor-内置输入组件

封装的输入组件 InputCheckbox:表示复选框。InputDate:表示类型为 date 的日期选择框。InputFile:表示文件上传。InputNumber:表示数字框。InputRadio:表示单选按钮。InputRadioGroup:表示单选按钮组。Inpu…

Qt源码分析: QChildEvent

本文记录QChildEvent事件相关代码分析。 注1:限于笔者研究水平,难免有表述不当,欢迎批评指正。 注2:博文会不定期更新,敬请关注。 一、QChildEvent的发送 分析QObject::setParent代码,当修改父对象时&…

《Whisper :说明书 》

[论文] [模型卡] [Colab 示例] Whisper 是一种通用的语音识别模型。它基于各种音频的大型数据集进行训练,也是一种多任务模型,可以执行多语言语音识别、语音翻译和语言识别。 方法 Transformer 序列到序列模型针对各种语音处理任务进行训练,…

回溯----8.N皇后

题目链接 /** 将n个棋子放在n*n的棋盘上,不同列,不同行,不同斜线 大致执行流程: 首先选取第一行第一格放置第一个棋子,再从第二行第一个位置开始选取合法的位置(不同行不同列不同斜线)放置棋子,重复上述流程迭代行数, 直到放置n个棋子。 若放置途中出现无合法位置的情况,回溯将…

微机电子拉伸试验机

对于不同材料的试样,由于其化学成分及组织的不同,在拉伸过程中会体现 出不同的物理现象及力学性质。西安力创(LETRY)公司专业制造WDL/WDW系列微机控制电子万能试验机,主要适用于金属板材、棒材、管材、金属丝、金属箔、…

【数据结构与算法】数据结构核心概念系统梳理

第一章 绪论:基础概念体系 🚩算法:问题求解步骤的描述。 🚩非递归的算法效率更高。 1.1 逻辑结构 vs 存储结构 维度逻辑结构存储结构(物理结构)定义数据元素之间的逻辑关系数据结构在计算机中的实现方式分类线性/树形/图/集合顺序/链式/索引/散列独立性独立于存储结构…

73页PPT | 大数据平台规划与数据价值挖掘应用咨询项目解决方案

推荐摘要:在数字化浪潮中,企业数据量呈几何级增长,却常因缺乏科学规划的大数据平台,陷入数据孤岛、处理效率低下的困境,难以充分挖掘数据价值。特推出大数据平台规划与数据价值挖掘应用咨询项目解决方案,正…

gRPC 与 Protobuf 的深度集成 —— 从服务定义到多语言交互(Go + Java 示例)

在前几篇文章中,我们已经掌握了 Protobuf 的基础语法、高级特性和序列化反序列化操作。本篇文章将深入讲解 gRPC 与 Protobuf 的集成,重点介绍如何通过 .proto 文件定义服务接口,并在 Go 和 Java 中实现 gRPC 服务与客户端的完整交互流程。我…

可信计算的基石:TPM技术深度解析与应用实践

可信计算的基石:TPM技术深度解析与应用实践 引言:数字世界的"信任之锚" 在数据泄露事件频发的时代,传统软件级安全防护已力不从心。TPM(可信平台模块)作为硬件级安全解决方案,正成为现代计算设…