理论看再多不如动手写代码。这一章我们从头搭建一个简单的用户管理示例,覆盖 GORM 最常用的功能。
myapp/
├── main.go
├── models/
│ └── user.go
└── go.mod
mkdir myapp && cd myapp
go mod init myapp
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
用 SQLite 作为示例数据库,省去安装数据库的麻烦。
创建 models/user.go:
package models
import "gorm.io/gorm"
type User struct {
gorm.Model
Name string `gorm:"size:100;not null"`
Email string `gorm:"size:100;uniqueIndex"`
Age int
}
gorm.Model 是 GORM 内置的结构体,包含四个常用字段:
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
嵌入它就自动有了主键、创建时间、更新时间、软删除字段。
创建 main.go:
package main
import (
"fmt"
"log"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"myapp/models"
)
var DB *gorm.DB
func initDB() {
var err error
DB, err = gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
log.Fatal("连接数据库失败:", err)
}
// 自动迁移
DB.AutoMigrate(&models.User{})
fmt.Println("数据库连接成功")
}
func main() {
initDB()
// 创建用户
createUser()
// 查询用户
queryUser()
// 更新用户
updateUser()
// 删除用户
deleteUser()
}
func createUser() {
user := models.User{
Name: "张三",
Email: "zhangsan@example.com",
Age: 25,
}
result := DB.Create(&user)
if result.Error != nil {
log.Println("创建失败:", result.Error)
return
}
fmt.Printf("创建成功,ID: %d\n", user.ID)
}
Create 方法返回一个 *gorm.DB 对象,可以获取:
result.Error - 错误信息result.RowsAffected - 影响的行数user.ID - 插入后的主键值批量创建:
users := []models.User{
{Name: "李四", Email: "lisi@example.com", Age: 28},
{Name: "王五", Email: "wangwu@example.com", Age: 30},
}
DB.Create(&users)
func queryUser() {
var user models.User
// 根据主键查询
result := DB.First(&user, 1)
if result.Error != nil {
log.Println("查询失败:", result.Error)
return
}
fmt.Printf("查询结果: %+v\n", user)
}
常用查询方法:
// 根据主键
DB.First(&user, 1) // SELECT * FROM users WHERE id = 1
DB.First(&user, "id = ?", 1) // 同上
// 根据条件
DB.Where("name = ?", "张三").First(&user)
// 查询所有
var users []models.User
DB.Find(&users)
// 条件查询
DB.Where("age > ?", 20).Find(&users)
// 排序和限制
DB.Order("age desc").Limit(10).Find(&users)
func updateUser() {
var user models.User
DB.First(&user, 1)
// 更新单个字段
DB.Model(&user).Update("age", 26)
// 更新多个字段
DB.Model(&user).Updates(models.User{
Name: "张三更新",
Age: 27,
})
// 用 map 更新
DB.Model(&user).Updates(map[string]interface{}{
"name": "张三",
"age": 28,
})
fmt.Println("更新成功")
}
Update 和 Updates 的区别:
Update 更新单个字段Updates 更新多个字段,可以用结构体或 mapfunc deleteUser() {
var user models.User
DB.First(&user, 1)
// 软删除(因为有 DeletedAt 字段)
DB.Delete(&user)
fmt.Println("删除成功")
}
因为模型嵌入了 gorm.Model,删除操作是软删除——记录不会真正删除,只是把 deleted_at 设为当前时间。
查询时会自动排除软删除的记录:
DB.Find(&users) // 不包含软删除的
DB.Unscoped().Find(&users) // 包含软删除的
真正删除:
DB.Unscoped().Delete(&user)
package main
import (
"fmt"
"log"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
type User struct {
gorm.Model
Name string `gorm:"size:100"`
Email string `gorm:"size:100;uniqueIndex"`
Age int
}
func main() {
// 连接数据库
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
log.Fatal(err)
}
// 迁移
db.AutoMigrate(&User{})
// 清空表
db.Exec("DELETE FROM users")
// 创建
user := User{Name: "张三", Email: "zhangsan@example.com", Age: 25}
db.Create(&user)
fmt.Printf("创建: %+v\n", user)
// 查询
var found User
db.First(&found, user.ID)
fmt.Printf("查询: %+v\n", found)
// 更新
db.Model(&found).Update("age", 26)
db.First(&found, user.ID)
fmt.Printf("更新后: %+v\n", found)
// 删除
db.Delete(&found)
// 验证删除
var count int64
db.Model(&User{}).Count(&count)
fmt.Printf("删除后记录数: %d\n", count)
}
运行:
go run main.go
输出:
创建: {Model:{ID:1 CreatedAt:2024-01-01 10:00:00 UpdatedAt:2024-01-01 10:00:00 DeletedAt:{Time:0001-01-01 00:00:00 Valid:false}} Name:张三 Email:zhangsan@example.com Age:25}
查询: {Model:{ID:1 ...} Name:张三 Email:zhangsan@example.com Age:25}
更新后: {Model:{ID:1 ...} Name:张三 Email:zhangsan@example.com Age:26}
删除后记录数: 0
通过这个示例,我们体验了 GORM 的核心功能:
gorm.Model)AutoMigrate)Create)First、Find)Update、Updates)Delete,软删除)这些操作覆盖了 80% 的日常使用场景。后面的章节会深入每个功能的细节。