Skip to content
鼓励作者:欢迎打赏犒劳

gorm初体验

数据库表

sql
CREATE TABLE `users` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `email` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `age` tinyint(3) unsigned NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


CREATE TABLE `articles` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL,
  `content` text COLLATE utf8mb4_unicode_ci,
  `user_id` bigint(20) unsigned NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_articles_user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

mock数据

sql
INSERT INTO `test`.`users`(`id`, `name`, `email`, `age`, `created_at`, `updated_at`) VALUES (1, '张三', 'zhangsan@example.com', 25, '2025-09-16 12:53:22', '2025-09-16 12:53:22');
INSERT INTO `test`.`users`(`id`, `name`, `email`, `age`, `created_at`, `updated_at`) VALUES (2, '李四', 'lisi@example.com', 30, '2025-09-16 12:53:22', '2025-09-16 12:53:22');
INSERT INTO `test`.`users`(`id`, `name`, `email`, `age`, `created_at`, `updated_at`) VALUES (3, '赵六', 'zhaoliu@example.com', 35, '2025-09-16 12:53:22', '2025-09-16 12:53:22');


INSERT INTO `test`.`articles`(`id`, `title`, `content`, `user_id`, `created_at`, `updated_at`) VALUES (1, 'GORM使用指南', '这是一篇关于GORM的详细教程...', 1, '2025-09-16 12:53:22', '2025-09-16 12:53:22');
INSERT INTO `test`.`articles`(`id`, `title`, `content`, `user_id`, `created_at`, `updated_at`) VALUES (2, 'Go语言入门', '学习Go语言的基础知识...', 1, '2025-09-16 12:53:22', '2025-09-16 12:53:22');
INSERT INTO `test`.`articles`(`id`, `title`, `content`, `user_id`, `created_at`, `updated_at`) VALUES (3, 'Web开发实战', '使用Go进行Web开发...', 2, '2025-09-16 12:53:22', '2025-09-16 12:53:22');
INSERT INTO `test`.`articles`(`id`, `title`, `content`, `user_id`, `created_at`, `updated_at`) VALUES (4, '数据库设计原则', '良好的数据库设计实践...', 3, '2025-09-16 12:53:22', '2025-09-16 12:53:22');

插入数据

go
package main

import (
	"fmt"
	"log"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 定义用户模型
type User struct {
	ID        uint      `gorm:"primaryKey"`           // 主键
	Name      string    `gorm:"size:100;not null"`    // 用户名,长度限制100,非空
	Email     string    `gorm:"size:100;uniqueIndex"` // 邮箱,长度限制100,唯一索引
	Age       uint8     `gorm:"check:age > 0"`        // 年龄,检查约束
	Articles  []Article `gorm:"foreignKey:UserID"`    // 用户拥有的文章列表
	CreatedAt time.Time // 创建时间
	UpdatedAt time.Time // 更新时间
}

// 定义文章模型(与用户是一对多关系)
type Article struct {
	ID        uint      `gorm:"primaryKey"`                                                      // 主键
	Title     string    `gorm:"size:200;not null"`                                               // 文章标题
	Content   string    `gorm:"type:text"`                                                       // 文章内容,使用文本类型
	UserID    uint      `gorm:"not null"`                                                        // 外键,关联用户ID
	User      User      `gorm:"foreignKey:UserID"` // 属于用户关系
	CreatedAt time.Time // 创建时间
	UpdatedAt time.Time // 更新时间
}

func main() {
	// MySQL 连接配置
	// 格式: "user:password@tcp(host:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"

	// 连接数据库
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info), // 设置日志级别为Info,显示所有SQL
	})
	if err != nil {
		log.Fatal("Failed to connect to database:", err)
	}

	// 获取底层的 sql.DB 对象并设置连接池
	sqlDB, err := db.DB()
	if err != nil {
		log.Fatal("Failed to get database instance:", err)
	}

	// 设置连接池参数
	sqlDB.SetMaxIdleConns(10)           // 最大空闲连接数
	sqlDB.SetMaxOpenConns(100)          // 最大打开连接数
	sqlDB.SetConnMaxLifetime(time.Hour) // 连接的最大可复用时间

	// 插入Mock数据
	insertMockData(db)
	
	// 关闭数据库连接
	if err := sqlDB.Close(); err != nil {
		log.Fatal("Failed to close database:", err)
	}
}

// 插入Mock数据
func insertMockData(db *gorm.DB) {
	// 先清空表
	db.Exec("DELETE FROM articles")
	db.Exec("DELETE FROM users")

	// 创建用户
	users := []User{
		{Name: "张三", Email: "zhangsan@example.com", Age: 25},
		{Name: "李四", Email: "lisi@example.com", Age: 30},
		{Name: "赵六", Email: "zhaoliu@example.com", Age: 35},
	}

	for i := range users {
		result := db.Create(&users[i])
		if result.Error != nil {
			log.Fatal("Failed to create user:", result.Error)
		}
	}

	// 创建文章
	articles := []Article{
		{Title: "GORM使用指南", Content: "这是一篇关于GORM的详细教程...", UserID: users[0].ID},
		{Title: "Go语言入门", Content: "学习Go语言的基础知识...", UserID: users[0].ID},
		{Title: "Web开发实战", Content: "使用Go进行Web开发...", UserID: users[1].ID},
		{Title: "数据库设计原则", Content: "良好的数据库设计实践...", UserID: users[2].ID},
	}

	for i := range articles {
		result := db.Create(&articles[i])
		if result.Error != nil {
			log.Fatal("Failed to create article:", result.Error)
		}
	}

	fmt.Println("Mock数据插入完成")
}

查询数据

go
package main

import (
	"fmt"
	"log"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 定义用户模型
type User struct {
	ID        uint      `gorm:"primaryKey"`           // 主键
	Name      string    `gorm:"size:100;not null"`    // 用户名,长度限制100,非空
	Email     string    `gorm:"size:100;uniqueIndex"` // 邮箱,长度限制100,唯一索引
	Age       uint8     `gorm:"check:age > 0"`        // 年龄,检查约束
	Articles  []Article `gorm:"foreignKey:UserID"`    // 用户拥有的文章列表
	CreatedAt time.Time // 创建时间
	UpdatedAt time.Time // 更新时间
}

// 定义文章模型(与用户是一对多关系)
type Article struct {
	ID        uint      `gorm:"primaryKey"`        // 主键
	Title     string    `gorm:"size:200;not null"` // 文章标题
	Content   string    `gorm:"type:text"`         // 文章内容,使用文本类型
	UserID    uint      `gorm:"not null"`          // 外键,关联用户ID
	User      User      `gorm:"foreignKey:UserID"` // 属于用户关系
	CreatedAt time.Time // 创建时间
	UpdatedAt time.Time // 更新时间
}

func main() {
	// MySQL 连接配置
	// 格式: "user:password@tcp(host:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"

	// 连接数据库
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info), // 设置日志级别为Info,显示所有SQL
	})
	if err != nil {
		log.Fatal("Failed to connect to database:", err)
	}

	// 获取底层的 sql.DB 对象并设置连接池
	sqlDB, err := db.DB()
	if err != nil {
		log.Fatal("Failed to get database instance:", err)
	}

	// 设置连接池参数
	sqlDB.SetMaxIdleConns(10)           // 最大空闲连接数
	sqlDB.SetMaxOpenConns(100)          // 最大打开连接数
	sqlDB.SetConnMaxLifetime(time.Hour) // 连接的最大可复用时间

	// 示例:查询所有用户及其文章
	fmt.Println("=== 所有用户及其文章 ===")
	var users []User
	db.Preload("Articles").Find(&users) // Preload预加载关联的文章
	for _, user := range users {
		fmt.Printf("用户: %s (%d岁), 邮箱: %s\n", user.Name, user.Age, user.Email)
		for _, article := range user.Articles {
			fmt.Printf("  - 文章: 《%s\n", article.Title)
		}
	}
    // 关闭数据库连接
	if err := sqlDB.Close(); err != nil {
		log.Fatal("Failed to close database:", err)
	}
}

where 条件查询

go
// 示例:条件查询
fmt.Println("\n=== 年龄大于25岁的用户 ===")
var olderUsers []User
db.Where("age > ?", 25).Find(&olderUsers)
for _, user := range olderUsers {
    fmt.Printf("用户: %s (%d岁)\n", user.Name, user.Age)
}

update 更新数据

go
// 示例:更新用户信息
fmt.Println("\n=== 更新用户信息 ===")
// 先查询用户
var userToUpdate User
db.First(&userToUpdate, "email = ?", "lisi@example.com")

// 更新年龄
db.Model(&userToUpdate).Update("age", 31)
fmt.Printf("用户 %s 年龄更新为: %d\n", userToUpdate.Name, userToUpdate.Age)

事务操作

go
// 示例:事务操作 - 创建用户同时创建文章
fmt.Println("\n=== 事务操作 - 创建用户同时创建文章 ===")
err = db.Transaction(func(tx *gorm.DB) error {
    // 在事务中执行一些数据库操作
    newUserWithArticle := User{
        Name:  "钱七",
        Email: "qianqi@example.com",
        Age:   32,
    }
    if err := tx.Create(&newUserWithArticle).Error; err != nil {
        // 返回任何错误都会回滚事务
        return err
    }

    newArticle := Article{
        Title:   "事务操作示例",
        Content: "这是一个演示事务操作的示例文章...",
        UserID:  newUserWithArticle.ID,
    }
    if err := tx.Create(&newArticle).Error; err != nil {
        return err
    }

    // 返回 nil 提交事务
    return nil
})

if err != nil {
    log.Fatal("Transaction failed:", err)
}
fmt.Println("事务操作成功完成")

删除用户

go
// 示例:删除用户(物理删除)
fmt.Println("\n=== 删除用户 ===")
// 先查询用户
var userToDelete User
result := db.First(&userToDelete, "email = ?", "lisi@example.com")

// 检查查询结果
if result.Error != nil {
    if errors.Is(result.Error, gorm.ErrRecordNotFound) {
        fmt.Printf("未找到邮箱为 %s 的用户,无需删除\n", "zhangsan@example.com")
    } else {
        log.Fatal("查询用户时出错:", result.Error)
    }
} else {
    // 打印查询到的用户信息
    fmt.Printf("找到用户: %s (ID: %d, 年龄: %d)\n",
        userToDelete.Name, userToDelete.ID, userToDelete.Age)

    result2 := db.Delete(&userToDelete)
    if result2.Error != nil {
        log.Fatal("Failed to delete user:", result2.Error)
    }
    fmt.Printf("用户 %s 已删除,影响行数: %d\n", userToDelete.Name, result2.RowsAffected)
}

原生查询

类似mybatis那种的结果映射

单对象映射

go
package main

import (
	"errors"
	"fmt"
	"log"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// 定义用户模型
type User struct {
	ID        uint      `gorm:"primaryKey"`           // 主键
	Name      string    `gorm:"size:100;not null"`    // 用户名,长度限制100,非空
	Email     string    `gorm:"size:100;uniqueIndex"` // 邮箱,长度限制100,唯一索引
	Age       uint8     `gorm:"check:age > 0"`        // 年龄,检查约束
	Articles  []Article `gorm:"foreignKey:UserID"`    // 用户拥有的文章列表
	CreatedAt time.Time // 创建时间
	UpdatedAt time.Time // 更新时间
}

// 定义文章模型(与用户是一对多关系)
type Article struct {
	ID        uint      `gorm:"primaryKey"`        // 主键
	Title     string    `gorm:"size:200;not null"` // 文章标题
	Content   string    `gorm:"type:text"`         // 文章内容,使用文本类型
	UserID    uint      `gorm:"not null"`          // 外键,关联用户ID
	User      User      `gorm:"foreignKey:UserID"` // 属于用户关系
	CreatedAt time.Time // 创建时间
	UpdatedAt time.Time // 更新时间
}

// 定义一个结构体来映射查询结果
type UserResult struct {
	Id        uint      `gorm:"column:id"` // 使用标签指定列名
	Name      string    `gorm:"column:name"`
	Email     string    `gorm:"column:email"`
	Age       int       `gorm:"column:age"`
	CreatedAt time.Time `gorm:"column:created_at"`
}

func main() {
	// MySQL 连接配置
	// 格式: "user:password@tcp(host:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"

	// 连接数据库
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.Default.LogMode(logger.Info), // 设置日志级别为Info,显示所有SQL
	})
	if err != nil {
		log.Fatal("Failed to connect to database:", err)
	}

	// 获取底层的 sql.DB 对象并设置连接池
	sqlDB, err := db.DB()
	if err != nil {
		log.Fatal("Failed to get database instance:", err)
	}

	// 设置连接池参数
	sqlDB.SetMaxIdleConns(10)           // 最大空闲连接数
	sqlDB.SetMaxOpenConns(100)          // 最大打开连接数
	sqlDB.SetConnMaxLifetime(time.Hour) // 连接的最大可复用时间

	// 示例 1: 查询单个用户信息
	var user UserResult
	userId := 3
	// 使用 Raw 执行原生 SQL 查询,并通过 Scan 将结果映射到结构体
	result := db.Raw("SELECT id, name, email, age, created_at FROM users WHERE id = ?", userId).Scan(&user)
	if result.Error != nil {
		// 检查是否是"记录未找到"的错误
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			fmt.Printf("未找到ID为 %d 的用户\n", userId)
		} else {
			log.Fatal("查询执行失败:", result.Error)
		}
	} else {
		fmt.Printf("用户信息: %+v\n", user)
	}
}

多对象映射

go
// 示例: 查询多个用户信息
var users []UserResult
userId := 2
// 使用 Raw 执行原生 SQL 查询,并通过 Scan 将结果映射到结构体
result := db.Raw("SELECT id, name, email, age, created_at FROM users WHERE id >= ?", userId).Scan(&users)
if result.Error != nil {
    log.Fatal("查询执行失败:", result.Error)
} else {
    for _, user := range users {
        fmt.Printf("用户信息: %+v\n", user)
    }

}

更新删除操作

go
// 示例 5: 执行更新操作并获取影响行数
newAge := 30
updateResult := db.Exec("UPDATE users SET age = ? WHERE age < ?", newAge, 25)
if updateResult.Error != nil {
    log.Fatal("Failed to execute update:", updateResult.Error)
}
rowsAffected := updateResult.RowsAffected
fmt.Printf("更新了 %d 行数据\n", rowsAffected)

如有转载或 CV 的请标注本站原文地址