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

news2024/11/25 8:14:06

GORM的CRUD教程

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

创建的

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

步骤 1: 定义模型

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

type User struct {
    gorm.Model
    Name    string
    Age     int
    Email   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 main

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "log"
)

type User struct {
    gorm.Model
    Name  string
    Age   int
    Email 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.Model
    Name    string
    Age     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.Model
    Name string
    Bio  *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 string
    err := sql.Scan(src, &str)
    if err != nil {
        return err
    }
    ct.value = str
    return nil
}

func (ct CustomType) Value() (driver.Value, error) {
    if ct.value == "" {
        return "default_value", nil // 返回默认值
    }
    return ct.value, nil
}

type User struct {
    gorm.Model
    Name string
    Data 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.Model
    Name string
    Age  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 main

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "log"
    "time"
)

type CustomType struct {
    value string
}

func (ct *CustomType) Scan(src interface{}) error {
    var str string
    err := sql.Scan(src, &str)
    if err != nil {
        return err
    }
    ct.value = str
    return nil
}

func (ct CustomType) Value() (driver.Value, error) {
    if ct.value == "" {
        return "default_value", nil // 返回默认值
    }
    return ct.value, nil
}

type User struct {
    gorm.Model
    Name    string
    Age     int           `gorm:"default:30"`
    Bio     *string
    Data    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 User
    db.First(&createdUser, "name = ?", "Alice")
    log.Printf("Created User: %+v\n", createdUser)
}

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

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

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

相关文章

第5讲:Sysmac Studio中的硬件拓扑

Sysmac Studio软件概述 一、创建项目 在打开的软件中选择新建工程 然后在工程属性中输入工程名称,作者,类型选择“标准工程”即可。 在选择设备处,类型选择“控制器”。 在版本处,可以在NJ控制器的硬件右侧标签处找到这样一个版本号。 我们今天用到的是1.40,所以在软…

DB-GPT:LLM应用的集大成者

整体架构 架构解读 可以看到,DB-GPT把架构抽象为7层,自下而上分别为: 运行环境:支持本地/云端&单机/分布式等部署方式。顺便一提,RAY是蚂蚁深度参与的一个开源项目,所以对RAY功能的支持应该非常完善。…

Hadoop、HDFS、MapReduce 大数据解决方案

本心、输入输出、结果 文章目录 Hadoop、HDFS、MapReduce 大数据解决方案前言HadoopHadoop 主要组件的Web UI端口和一些基本信息MapReduceMapReduce的核心思想MapReduce的工作流程MapReduce的优缺点Hadoop、HDFS、MapReduce 大数据解决方案 编辑 | 简简单单 Online zuozuo 地址…

从输入 URL 到页面展示到底发生了什么

从输入 URL 到页面展示到底发生了什么呢? 1.在浏览器输入一个域名回车 2.首先会先检查浏览器缓存里是否有缓存资源,如果缓存中有,会直接在浏览器上显示页面内容,如果没有,在发送http请求之前,浏览器会向D…

基于FPGA的以太网设计(2)----以太网的硬件架构(MAC+PHY)

1、概述 以太网的电路架构一般由MAC、PHY、变压器、RJ45和传输介质组成,示意图如下所示: 需要注意的是,上图是一个简化了的模型,它描述的是两台主机之间的直接连接,但在实际应用中基本都是多台主机构成的局域网,它们之间并不直接相连,而是通过交换机Switch来进行…

跟代码执行流程,读Megatron源码(四)megatron训练脚本initialize.py之initialize_megatron()分布式环境初始化

在前文中,我们讲述了pretrain函数的执行流程,其首要步骤是megatron分组的初始化与环境的配置。本文将深入initialize_megatron函数源码,剖析其初始化分布式训练环境的内部机制。 注:在此假设读者具备3D并行相关知识 一. initiali…

Linux基于CentOS7【yum】【vim】的基础学习,【普通用户提权】

目录 yum生态 什么是yum yum是如何得知目标服务器的地址和下载链接 vim vim模式 命名模式 光标移动 插入模式 i键插 a键插 o键插 底行模式 批量化注释 批量化去注释 创建vim配置文件 例子 高亮功能: 缩进功能: 符号位自动补齐功能…

软件缺陷(Bug)、禅道

目录 软件缺陷的判定标准 软件缺陷的核心内容 构成缺陷的基本要素 缺陷报告 缺陷管理 缺陷的跟踪流程 项目管理工具--禅道 软件在使用过程中存在的任何问题(如:错误、异常等),都叫软件的缺陷,简称bug。 软件缺…

175道Docker面试题(上)

目录 1、什么是docker? 2、Docker与普通虚拟机的对比: 3、Docker常用命令: 4、Docker镜像是什么? 5、Docker容器是什么? 6、Docker容器有几种状态? 7、Dockerfile中最常见的指令是什么? …

v-for 进行列表的 增删改查

通过对象下标替换属性值 但是通过实践此方法是错误的&#xff0c;Vue监听的是students这个对象&#xff0c;而不是这个对象里面的数组信息&#xff0c;也就是说&#xff0c;改变里面的值&#xff0c;并不能在页面上实现更新的功能 <!DOCTYPE html> <html lang"en…

windows系统conda 使用注意事项

在windows系统中&#xff0c;可以直接在Anaconda 的终端中使用conda功能。 但是&#xff0c;在Anaconda的终端中&#xff0c; 无法使用完整的命令行工具。 如设置环境变量的set命令就不起作用。 这时我们就想要在windows的cmd命令中直接使用conda。 但直接使用会有问题&#…

HarmonyOS NEXT零基础入门到实战-第四部分

自定义组件: 概念: 由框架直接提供的称为 系统组件&#xff0c; 由开发者定义的称为 自定义组件。 源代码&#xff1a; Component struct MyCom { build() { Column() { Text(我是一个自定义组件) } } } Component struct MyHeader { build() { Row(…

Maven的常用命令(面试篇之Maven)

我在写项目时,使用Maven的插件的命令来进行打包等,却发现报错误了,虽然解决了, 但借此机会来总结一下Maven的常用命令: 这些插件都有着自己的命令,虽然,我们可以简化的使用一些idea中的方便的按键: 但 , 一个程序员的功力深浅就在这些细节末尾处: 在Maven中&#xff0c;插件是…

高职国培丨数据分析与数据挖掘课程实施能力提升培训班正式开班

7月15日&#xff0c;由广东机电职业技术学院牵头&#xff0c;广东泰迪智能科技股份有限公司作为合作单位的“高职教师数据分析与数据挖掘课程实施能力提升培训班&#xff08;高职国培&#xff09;”正式开班。来自广东省各地36位高校教师参与本次线下师资国培班。 广东机电职业…

el-menu根据多层树形结构递归遍历展示菜单栏

文章目录 前提条件假设菜单等级只有两个等级结果如下所示 但是如果菜单等级超过两个等级或者多个等级的话App.vueMenuItems.vue结果如下所示 关于遍历时图标前的展示后续完善关于点击路由跳转参考element plus的官网即可 前提条件 package.json如下所示&#xff0c;这是一个Vi…

广州邀请媒体宣传(附媒体名单)

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 广州地区 媒体邀约&#xff1a; 记者现场采访&#xff0c;电视台到场报道&#xff0c;展览展会宣传&#xff0c;广交会企业宣传&#xff0c;工厂探班&#xff0c;媒体专访等。 适合广州…

vue3前端开发-小兔鲜项目-二级页面面包屑导航和跳转

vue3前端开发-小兔鲜项目-二级页面面包屑导航和跳转&#xff01;这一次&#xff0c;做两件事。第一件事是把二级分类页面的跳转&#xff08;也就是路由&#xff09;设计一下。第二件事是把二级页面的面包屑导航设计一下。 第一件事&#xff0c;二级页面的跳转路由设计一下。 如…

【RabbitMQ】Windows下RabbitMQ的安装和部署

Windows下RabbitMQ的安装和部署 一、引言二、环境搭建三、安装ERLANG四、安装RabbitMQ五、安装RabbitMQ-Plugins六、验证 一、引言 RabbitMQ——Rabbit Message Queue的简写&#xff0c;但不能仅仅理解其为消息队列&#xff0c;消息代理更合适。RabbitMQ 是一个由 Erlang 语言…

智慧隧道可视化:安全与效率的智能保障

运用图扑可视化技术&#xff0c;实时监测隧道内的环境和交通状况&#xff0c;提升维保效率和应急响应能力&#xff0c;确保隧道运营的安全和畅通。

Build a Large Language Model (From Scratch)GPT-4o翻译和代码每行中文注释Ch5

目录 Pretraining on Unlabeled DataThis chapter covers5.1 Evaluating generative text models5.1.1 Using GPT to generate text5.1.2 Calculating the text generation loss5.1.3 Calculating the training and validation set losses 5.2 Training an LLM5.3 Decoding str…