当前位置: 首页 > news >正文

go语言Gin框架的学习路线(九)

GORM的CRUD教程

CRUD 是 "Create, Read, Update, Delete"(创建、读取、更新、删除)的缩写,代表了数据库操作的基本功能。在 GORM 的上下文中,CRUD 指的是使用 GORM 库来执行这些基本的数据库操作。

创建的

在 GORM 中创建记录通常使用 Create 方法。以下是一个创建记录的例子,包括定义模型、创建记录以及处理数据库连接:

步骤 1: 定义模型

首先,定义一个模型,通常是一个结构体,它内嵌了 GORM 的 Model 结构体来获得自动管理的字段,如 IDCreatedAtUpdatedAt 等。

type User struct {gorm.ModelName    stringAge     intEmail   string
}

步骤 2: 连接数据库

然后,使用 GORM 连接到数据库。这里以 SQLite 为例,实际使用中可以是 MySQL、PostgreSQL、SQL Server 等。

import ("gorm.io/driver/sqlite""gorm.io/gorm""log"
)func main() {dsn := "file:db.sqlite?mode=memory&cache=shared&_fk=1"db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})if err != nil {log.Fatal("Could not connect to the database", err)}defer db.Close()

步骤 3: 自动迁移

使用 AutoMigrate 方法来自动创建或更新数据库表,以匹配模型的结构。

// 自动迁移模式,确保数据库结构与 User 结构体一致
db.AutoMigrate(&User{})

步骤 4: 创建记录

使用 Create 方法创建新的记录。

    // 创建新用户user := User{Name: "Alice", Age: 30, Email: "alice@example.com"}db.Create(&user) // 使用 &user 因为 Create 需要指针来设置返回值
}

在这个例子中,Create 方法将 User 结构体的实例插入到数据库中。CreatedAt 字段会自动设置为当前时间戳,表示记录被创建的时间。如果记录成功创建,user 变量也会被更新,包括数据库生成的主键 ID

完整示例代码
package mainimport ("gorm.io/driver/sqlite""gorm.io/gorm""log"
)type User struct {gorm.ModelName  stringAge   intEmail string
}func main() {dsn := "file:db.sqlite?mode=memory&cache=shared&_fk=1"db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})if err != nil {log.Fatal("Could not connect to the database", err)}defer db.Close()db.AutoMigrate(&User{})user := User{Name: "Alice", Age: 30, Email: "alice@example.com"}db.Create(&user) // 注意 Create 方法需要一个指针// 打印创建的用户信息log.Printf("Created User: %+v\n", user)
}

这个示例程序展示了如何使用 GORM 来定义一个模型、连接到数据库、自动创建表结构、插入一条新记录,并打印这条记录。这整个过程就是数据库操作中的 "Create"(创建)部分。通过 GORM,你可以用面向对象的方式来处理数据库的 CRUD 操作,而不需要编写复杂的 SQL 语句。

在 GORM 中,创建记录时可以结合多种方式来设置默认值。

以下是一些方法和示例,展示如何在创建记录时使用这些功能:

1. 使用 Tag 定义字段的默认值

你可以在结构体字段的 tag 中使用 default 关键字来指定默认值。

type User struct {gorm.ModelName    stringAge     int    `gorm:"default:30"`Email   string `gorm:"default:'noreply@example.com'"`
}

在这个例子中,如果创建 User 时没有指定 AgeEmail,它们将自动被设置为 30'noreply@example.com'

GORM 的 tag 允许你为字段指定额外的选项,这些选项在数据库迁移、记录创建和查询时会被 GORM 识别和使用。在这个例子中,default 关键字用于指定字段的默认值。 

2. 使用指针方式实现零值存入数据库

通过使用指针类型,你可以在创建记录时将某些字段设置为 SQL 的 NULL 值。

type User struct {gorm.ModelName stringBio  *string
}

如果 Bionil,它在数据库中将被存储为 NULL。

  • Bio: 一个指向字符串的指针 *string。这里的指针用法有几个目的:

    • NULL 值: 在 SQL 中,指针可以用来表示 NULL 值。如果 Bio 被初始化为 nil,那么在数据库中对应的字段将存储为 NULL。
    • 可选字段: 指针表示这个字段是可选的,不是必须的。只有当 Bio 被赋予了一个非 nil 的值时,才会在数据库中存储一个实际的字符串。
    • 空字符串与 NULL 的区分: 如果字段是 *string 类型,你可以区分空字符串 ("") 和 NULL。空字符串是一个有效的字符串值,而 NULL 表示字段没有值。

3. 使用 Scanner/Valuer 接口方式实现零值存入数据库

通过实现 sql.Scannerdriver.Valuer 接口,你可以控制字段的默认行为。

type CustomType struct {value string
}func (ct *CustomType) Scan(src interface{}) error {var str stringerr := sql.Scan(src, &str)if err != nil {return err}ct.value = strreturn nil
}func (ct CustomType) Value() (driver.Value, error) {if ct.value == "" {return "default_value", nil // 返回默认值}return ct.value, nil
}type User struct {gorm.ModelName stringData CustomType `gorm:"not null"`
}

在这个例子中,如果 Data.value 是空字符串,Value() 方法将返回 "default_value" 作为默认值。

代码理解

  • CustomType 的 Scan 方法允许你在从数据库检索记录时自定义如何将数据库中的值(通常是字符串)转换为 CustomType 类型的字段。
  • CustomType 的 Value 方法允许你在将记录保存到数据库时自定义如何将 CustomType 类型的字段转换为数据库中的值。在这个例子中,如果 value 是空字符串,它将使用 "default_value" 作为默认值。
  • User 结构体中的 Data 字段使用 CustomType,这意味着在数据库操作中,Data 字段的值将通过 CustomType 的 Scan 和 Value 方法进行转换。
  • gorm:"not null" tag 指示 GORM 在数据库中对应的列不允许为空值。如果使用 Data 作为字段类型,你需要确保在调用 Value 方法时总是返回一个非 NULL 的数据库值。

示例应用

这个自定义类型和接口实现可以用于处理那些需要特殊处理的数据库字段,例如,加密字段、格式特定的字段,或者像这里的示例,当数据库字段可能为空但你想提供一个默认值的情况。

4. 扩展创建选项

你可以使用 Create 方法的选项来自定义创建行为,例如设置默认值。

user := User{Name: "Alice"}
db.Clauses(clause.Expr{SQL: "SET", Name: "age", Value: 30}).Create(&user)

在这个例子中,Clauses 方法用于添加额外的 SQL 表达式,这里使用了 SET 来在创建记录时设置 age 字段的默认值。

5. 使用钩子(Hooks)

GORM 提供了钩子(如 BeforeCreate),在创建记录之前可以设置默认值。

type User struct {gorm.ModelName stringAge  int
}func (u *User) BeforeCreate(tx *gorm.DB) error {if u.Age == 0 {u.Age = 30 // 如果 Age 是 0,设置默认值}return nil
}

在这个例子中,BeforeCreate 钩子会在记录被创建之前被调用,允许你在记录保存到数据库之前修改字段值。

  • BeforeCreate 是一个在 GORM 创建记录之前自动调用的方法。它是一个钩子,允许你在记录被保存到数据库之前执行自定义逻辑。
  • 这个方法接收一个 *gorm.DB 类型的参数 tx,表示当前的数据库事务。
  • 在这个钩子中,如果 User 的 Age 字段值为 0,它将 Age 设置为 30 作为默认值。
  • 钩子函数返回 nil 表示没有错误,允许 GORM 继续执行创建记录的操作。

钩子的工作流程

  1. 当你调用 db.Create(&user) 来创建一个新的 User 记录时,GORM 会触发 BeforeCreate 钩子。
  2. 在 BeforeCreate 钩子中,你可以访问和修改 user 的字段,例如在这里检查 Age 是否为 0 并设置默认值。
  3. 钩子函数执行完毕后,GORM 会根据修改后的 user 字段的值创建数据库记录。

示例应用

这个钩子非常有用,特别是当你需要在记录保存到数据库之前执行一些验证、计算或设置默认值时。通过使用钩子,你可以保持你的业务逻辑和数据访问代码分离,同时确保数据的一致性和完整性。

注意

  • 钩子函数应该总是返回 nil 错误,除非你想要阻止 GORM 继续执行创建操作。
  • 钩子函数提供了对当前事务的引用,这意味着你可以在钩子中执行额外的数据库操作,例如查询或更新其他记录。

通过这种方式,GORM 的钩子提供了一个强大的机制来自定义数据库操作流程。

在 GORM 中,钩子(Hooks)的作用是在特定的数据库操作事件之前或之后自动执行代码。这些钩子可以视为拦截器或回调函数,它们允许你在 GORM 执行标准 CRUD 操作的过程中插入自定义逻辑。

钩子的主要作用包括:

  1. 设置默认值

    • 在创建或更新记录之前,可以设置字段的默认值。
  2. 验证数据

    • 在创建或更新记录之前,可以验证数据的有效性,如果数据不符合要求,可以返回错误以中断操作。
  3. 修改字段值

    • 在记录保存到数据库之前,可以修改字段的值,例如,对密码进行加密处理。
  4. 执行额外的数据库操作

    • 可以在创建或更新记录的同时,执行其他数据库操作,如更新相关联的记录或触发级联删除。
  5. 记录操作日志

    • 可以在记录被创建或更新后,记录操作日志,用于审计或调试。
  6. 处理关联关系

    • 在创建或更新具有关联关系(如外键)的记录时,可以手动处理这些关系。
  7. 自动填充字段

    • 可以在记录创建或更新后,自动填充某些字段,如根据当前时间自动设置时间戳。
  8. 事务管理

    • 可以在钩子中执行事务的提交或回滚操作,以确保数据的一致性。

可用的钩子类型:

  • BeforeCreate(): 在记录创建之前调用。
  • AfterCreate(): 在记录创建之后调用。
  • BeforeSave(): 在记录保存之前调用,适用于创建和更新操作。
  • AfterSave(): 在记录保存之后调用,适用于创建和更新操作。
  • BeforeUpdate(): 在记录更新之前调用。
  • AfterUpdate(): 在记录更新之后调用。
  • BeforeDelete(): 在记录删除之前调用。
  • AfterDelete(): 在记录删除之后调用。
  • BeforeFind(): 在记录查询之前调用。
  • AfterFind(): 在记录查询之后调用。

示例代码

结合以上方法,以下是一个完整的示例,展示如何在创建记录时使用这些功能:

package mainimport ("gorm.io/driver/sqlite""gorm.io/gorm""log""time"
)type CustomType struct {value string
}func (ct *CustomType) Scan(src interface{}) error {var str stringerr := sql.Scan(src, &str)if err != nil {return err}ct.value = strreturn nil
}func (ct CustomType) Value() (driver.Value, error) {if ct.value == "" {return "default_value", nil // 返回默认值}return ct.value, nil
}type User struct {gorm.ModelName    stringAge     int           `gorm:"default:30"`Bio     *stringData    CustomType    `gorm:"not null"`
}func (u *User) BeforeCreate(tx *gorm.DB) error {if u.Age == 0 {u.Age = 30 // 如果 Age 是 0,设置默认值}if u.Bio == nil {u.Bio = new(string)*u.Bio = "This is a bio"}return nil
}func main() {dsn := "file:db.sqlite?mode=memory&cache=shared&_fk=1"db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})if err != nil {log.Fatal("Could not connect to the database", err)}defer db.Close()db.AutoMigrate(&User{})user := User{Name: "Alice", Bio: nil}db.Create(&user)var createdUser Userdb.First(&createdUser, "name = ?", "Alice")log.Printf("Created User: %+v\n", createdUser)
}

 期末放假自学Gin框架,希望我们可以一起学习!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 构造+位运算,CF 1901C - Add, Divide and Floor
  • mac M1安装换脸Roop教程及所遇到的问题
  • 微信小程序:多图片显示及图片点击放大,多视频显示
  • git的一些使用技巧(git fetch 和 git pull的区别,git merge 和 git rebase的区别)
  • milvus的批量向量搜索
  • 数模·插值和拟合算法
  • 【Zotero插件】Zotero Tag为文献设置阅读状态 win11下相关设置
  • 上海市计算机学会竞赛平台2022年9月月赛丙组二叉树的遍历
  • 【JavaScript】 JS 的单线程和浏览器的多进程架构
  • PHP常量
  • 图灵测试:人工智能与人类沟通的界限
  • UniVue@v1.5.0版本发布:里程碑版本
  • linux学习笔记整理: 关于linux:nginx服务器 2024/7/20;
  • Ubuntu Grub引导优化
  • 基于微信小程序+SpringBoot+Vue的校园自助打印系统(带1w+文档)
  • @angular/forms 源码解析之双向绑定
  • 2017前端实习生面试总结
  • angular学习第一篇-----环境搭建
  • cookie和session
  • gops —— Go 程序诊断分析工具
  • IDEA 插件开发入门教程
  • mysql 数据库四种事务隔离级别
  • nodejs实现webservice问题总结
  • SpringBoot几种定时任务的实现方式
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • vue-router的history模式发布配置
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 关于for循环的简单归纳
  • 基于axios的vue插件,让http请求更简单
  • 如何实现 font-size 的响应式
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • 阿里云服务器如何修改远程端口?
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • ​Linux·i2c驱动架构​
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • (1)常见O(n^2)排序算法解析
  • (2)STL算法之元素计数
  • (6)STL算法之转换
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (多级缓存)缓存同步
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)python房屋租赁管理系统 毕业设计 745613
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (函数)颠倒字符串顺序(C语言)
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (三)SvelteKit教程:layout 文件
  • (三十五)大数据实战——Superset可视化平台搭建
  • (十三)MipMap
  • (图)IntelliTrace Tools 跟踪云端程序