GORM SQLite 教程:快速入门与实践
GORM(Go Object Relational Mapper)是 Golang 语言中最流行的 ORM 库之一,它提供了便捷的方式来连接和操作各种数据库,极大地简化了数据库操作的复杂性。SQLite 是一种轻量级的嵌入式数据库,它无需独立的服务器进程,直接将数据库存储在文件中,方便部署和携带。 本文将结合 GORM 和 SQLite,深入讲解如何使用 GORM 连接 SQLite 数据库,进行数据模型的定义、CRUD(创建、读取、更新、删除)操作、迁移、高级查询等,并通过实践案例,帮助你快速上手 GORM 和 SQLite 的开发。
一、准备工作
在开始之前,确保你已经安装了以下软件:
- Go: 确保你的 Go 版本是 1.13 或更高。可以从 https://golang.org/dl/ 下载安装。
- 文本编辑器或 IDE: 例如 VS Code, GoLand 等。
- (可选)SQLite 数据库管理工具: 例如 DB Browser for SQLite。 它可以帮助你可视化地查看和管理 SQLite 数据库。
二、安装 GORM 和 SQLite Driver
打开你的终端,进入你的 Go 项目目录,并使用以下命令安装 GORM 和 SQLite driver:
bash
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
这两个命令会下载并安装 GORM 的核心库和 SQLite 的 driver。 driver 负责 GORM 与 SQLite 数据库之间的连接和通信。
三、连接 SQLite 数据库
首先,创建一个 main.go
文件,并添加以下代码:
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 后续代码将在此处添加
}
“`
这段代码的作用如下:
- 导入必要的包: 导入了
fmt
(用于打印输出),log
(用于错误处理),gorm.io/gorm
(GORM 的核心库) 和gorm.io/driver/sqlite
(SQLite driver)。 gorm.Open()
函数: 使用gorm.Open()
函数连接 SQLite 数据库。sqlite.Open("test.db")
指定了数据库文件的路径和名称。如果文件不存在,GORM 会自动创建它。&gorm.Config{}
提供了一些配置选项,例如日志记录、连接池大小等。 你可以根据需要进行配置。- 错误处理: 检查连接是否成功。如果连接失败,程序会打印错误信息并退出。
- 成功连接提示: 如果连接成功,会打印一条消息到控制台。
运行 go run main.go
,如果一切顺利,你应该会看到 “Connected to SQLite database successfully!” 的消息。 同时,你的项目目录下会生成一个名为 test.db
的 SQLite 数据库文件。
四、定义数据模型
接下来,我们需要定义 Go 结构体来映射数据库表。 例如,我们定义一个 Product
结构体:
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
// 数据库code字段加上唯一索引
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 迁移 schema
db.AutoMigrate(&Product{})
// 后续代码将在此处添加
}
“`
这段代码新增了以下内容:
Product
结构体: 定义了一个Product
结构体,它包含了ID
,CreatedAt
,UpdatedAt
,DeletedAt
(来自gorm.Model
)、Code
和Price
字段。gorm.Model
: GORM 提供的默认模型,包含 ID(主键)、CreatedAt(创建时间)、UpdatedAt(更新时间)、DeletedAt(删除时间)。Code
: 商品代码,类型为字符串。gorm:"index:idx_code,unique"
是一个 GORM tag,它指定了在数据库中为Code
字段创建一个名为idx_code
的唯一索引。 唯一索引保证了Code
字段的值在表中是唯一的。Price
: 商品价格,类型为无符号整数。
db.AutoMigrate(&Product{})
: 使用AutoMigrate()
函数自动创建数据库表。 GORM 会根据Product
结构体的定义,在数据库中创建一个名为products
的表。 如果表已经存在,GORM 会自动更新表的 schema,以匹配结构体的定义。 注意:AutoMigrate
在生产环境中应该谨慎使用,因为它可能会导致数据丢失。 更好的做法是使用数据库迁移工具,手动编写 SQL 脚本来更新 schema。
再次运行 go run main.go
,GORM 会自动创建 products
表。 你可以使用 SQLite 数据库管理工具来查看表的结构。
五、CRUD 操作
现在,我们可以开始进行 CRUD 操作了。
1. 创建 (Create)
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
// 数据库code字段加上唯一索引
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 迁移 schema
db.AutoMigrate(&Product{})
// 创建一个 Product
product := Product{Code: "D42", Price: 100}
result := db.Create(&product) // 通过数据的指针来创建
if result.Error != nil {
log.Fatal("Failed to create product:", result.Error)
}
fmt.Println("Created product with ID:", product.ID)
fmt.Println("Affected rows:", result.RowsAffected)
}
“`
这段代码新增了以下内容:
- 创建
Product
实例: 创建了一个Product
结构体的实例,设置了Code
为 “D42” 和Price
为 100。 db.Create(&product)
: 使用db.Create()
函数将product
插入到数据库中。 注意: 需要传递结构体指针&product
,GORM 会自动填充ID
,CreatedAt
,UpdatedAt
等字段。- 结果处理:
db.Create()
函数返回一个*gorm.DB
对象,包含了操作的结果信息。result.Error
存储了错误信息,result.RowsAffected
存储了受影响的行数。 我们检查result.Error
,如果发生错误,打印错误信息并退出。 否则,打印新创建的product
的 ID 和受影响的行数。
运行 go run main.go
,你会在数据库的 products
表中看到一条新的记录。
2. 读取 (Read)
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
// 数据库code字段加上唯一索引
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 迁移 schema
db.AutoMigrate(&Product{})
// 创建一个 Product (如果数据库为空)
var count int64
db.Model(&Product{}).Count(&count)
if count == 0 {
product := Product{Code: "D42", Price: 100}
db.Create(&product)
}
// 读取 Product
var product Product
result := db.First(&product, 1) // 根据 ID 查询
// result := db.Where("code = ?", "D42").First(&product) // 根据 Code 查询
if result.Error != nil {
log.Fatal("Failed to find product:", result.Error)
}
fmt.Println("Found product:", product)
}
“`
这段代码新增了以下内容:
- 查询 Product: 使用
db.First(&product, 1)
根据 ID 查询 ID 为 1 的 Product。 或者,可以使用db.Where("code = ?", "D42").First(&product)
根据 Code 查询 Code 为 “D42” 的 Product。db.First()
和db.Where().First()
都会将查询结果填充到product
变量中。 - 结果处理: 检查
result.Error
,如果发生错误,打印错误信息并退出。 否则,打印查询到的product
的信息。 - 创建Product (如果数据库为空):
db.Model(&Product{}).Count(&count)
查询 Product 表有多少条记录,如果数据库是空的,就插入一条记录,保证可以查询到内容,方便测试。
运行 go run main.go
,你会看到查询到的 Product 的信息。
3. 更新 (Update)
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
// 数据库code字段加上唯一索引
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 迁移 schema
db.AutoMigrate(&Product{})
// 创建一个 Product (如果数据库为空)
var count int64
db.Model(&Product{}).Count(&count)
if count == 0 {
product := Product{Code: "D42", Price: 100}
db.Create(&product)
}
// 更新 Product
var product Product
db.First(&product, 1)
product.Price = 200
result := db.Save(&product) // 保存更改
if result.Error != nil {
log.Fatal("Failed to update product:", result.Error)
}
fmt.Println("Updated product:", product)
}
“`
这段代码新增了以下内容:
- 更新 Price: 首先查询 ID 为 1 的 Product,然后修改
product.Price
的值为 200。 db.Save(&product)
: 使用db.Save()
函数保存更改。db.Save()
会更新数据库中与product
匹配的记录。
运行 go run main.go
,你会看到 Product 的 Price 已经被更新为 200。
4. 删除 (Delete)
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
// 数据库code字段加上唯一索引
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 迁移 schema
db.AutoMigrate(&Product{})
// 创建一个 Product (如果数据库为空)
var count int64
db.Model(&Product{}).Count(&count)
if count == 0 {
product := Product{Code: "D42", Price: 100}
db.Create(&product)
}
// 删除 Product
var product Product
db.First(&product, 1)
result := db.Delete(&product) // 删除
if result.Error != nil {
log.Fatal("Failed to delete product:", result.Error)
}
fmt.Println("Deleted product")
}
“`
这段代码新增了以下内容:
db.Delete(&product)
: 使用db.Delete()
函数删除与product
匹配的记录。db.Delete()
默认会执行物理删除,即从数据库中永久删除记录。
运行 go run main.go
,你会发现 ID 为 1 的 Product 已经被删除。
六、高级查询
GORM 提供了丰富的高级查询功能,例如:
- 条件查询: 使用
Where()
函数指定查询条件。 - 排序: 使用
Order()
函数指定排序规则。 - 分页: 使用
Limit()
和Offset()
函数实现分页。 - 预加载: 使用
Preload()
函数预加载关联数据。 - 原生 SQL: 使用
Raw()
函数执行原生 SQL 查询。
以下是一个使用条件查询、排序和分页的示例:
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
// 数据库code字段加上唯一索引
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“test.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
fmt.Println("Connected to SQLite database successfully!")
// 迁移 schema
db.AutoMigrate(&Product{})
// 创建一些 Product (如果数据库为空)
var count int64
db.Model(&Product{}).Count(&count)
if count == 0 {
db.Create(&Product{Code: "D42", Price: 100})
db.Create(&Product{Code: "D43", Price: 200})
db.Create(&Product{Code: "D44", Price: 150})
}
// 高级查询
var products []Product
result := db.Where("price > ?", 120).
Order("price DESC").
Limit(2).
Offset(0).
Find(&products)
if result.Error != nil {
log.Fatal("Failed to find products:", result.Error)
}
fmt.Println("Found products:", products)
}
“`
这段代码查询 Price 大于 120 的 Product,按照 Price 降序排序,每页显示 2 条记录,显示第一页的结果。
七、实践案例:简单的商品管理系统
我们可以将 GORM 和 SQLite 应用到一个简单的商品管理系统中。 该系统可以实现以下功能:
- 添加商品
- 删除商品
- 修改商品信息
- 查询商品列表
完整的代码实现会比较长,这里只提供一个框架,你需要根据自己的需求完善代码。
“`go
package main
import (
“fmt”
“log”
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type Product struct {
gorm.Model
Code string gorm:"index:idx_code,unique"
Price uint
}
func main() {
db, err := gorm.Open(sqlite.Open(“products.db”), &gorm.Config{})
if err != nil {
log.Fatal(“Failed to connect to database:”, err)
}
db.AutoMigrate(&Product{})
for {
fmt.Println("1. 添加商品")
fmt.Println("2. 删除商品")
fmt.Println("3. 修改商品信息")
fmt.Println("4. 查询商品列表")
fmt.Println("5. 退出")
var choice int
fmt.Print("请选择操作:")
fmt.Scanln(&choice)
switch choice {
case 1:
// 添加商品
case 2:
// 删除商品
case 3:
// 修改商品信息
case 4:
// 查询商品列表
case 5:
fmt.Println("退出系统")
return
default:
fmt.Println("无效的选择")
}
}
}
“`
八、总结
本文详细介绍了如何使用 GORM 连接 SQLite 数据库,进行数据模型的定义、CRUD 操作、迁移、高级查询等。 通过学习本文,你应该能够快速上手 GORM 和 SQLite 的开发,并能够将它们应用到实际项目中。 GORM 提供了强大的功能和灵活的配置,可以帮助你简化数据库操作,提高开发效率。 SQLite 则以其轻量级和易用性,成为小型项目和嵌入式系统的理想选择。 希望本文能够帮助你更好地理解和使用 GORM 和 SQLite。