GORM CRUD 5 分钟快速上手

news2024/11/16 23:35:40

文章目录

  • 1.ORM 是什么
  • 2.GORM 是什么
  • 3.安装
  • 4.连接 DB
  • 5.创建数据表
  • 6.增加(Create)
  • 7.查询(Read)
  • 8.更新(Update)
  • 9.删除(Delete)
  • 10.小结
  • 参考文献

1.ORM 是什么

ORM(Object Relational Mapping),中文名为对象关系映射。

使用 ORM 组件,可以让开发者通过操作对象的方式完成对数据库的操作(读写),避免手动书写 SQL 和完成数据到对象的转换,让我们更方便的操作数据库。

理论上 ORM 可以让我们脱离 SQL,但实际上还是需要懂 SQL 才能更好地使用 ORM。

2.GORM 是什么

GORM 是一个流行的 Golang ORM 库。

类似于 Java 生态里大家听到过的 Mybatis、Hibernate、SpringData 等。

GORM 由国人开发,中文文档齐全,对开发者友好,支持主流关系型数据库。

  • MySQL
  • SQL Server
  • PostgreSQL
  • SQlite

GORM 功能丰富齐全:

  • 关联 (拥有一个,拥有多个,属于,多对多,多态,单表继承)
  • 钩子(before/after create/save/update/delete/find)
  • 支持 Preload、Joins 的预加载
  • 事务,嵌套事务,保存点,回滚到保存点
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,使用 Map Find/Create,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • 自动迁移
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
  • 每个特性都经过了测试的重重考验
  • 开发者友好

GORM 最新源码地址:go-gorm/gorm。

GORM V1 版本地址:jinzhu/gorm。

GORM 中文文档地址:这里。

本文将对 GORM 中常用的功能进行讲解,帮助你快速上手。

当然除了 GORM,你还有其他选择,比如 facebook-ent、sqlx 和 sqlc 等。

3.安装

基于 Go Module 开发,import 最新包然后 go get 即可。

go get -u gorm.io/gorm

// 不同 DB 对应的驱动
go get -u gorm.io/driver/sqlite
go get -u gorm.io/driver/mysql
go get -u gorm.io/driver/postgres
go get -u gorm.io/driver/sqlserver

驱动包按照自己实际使用的 DB 选择即可。

本文将以 MySQL 为例,讲解 GORM 的使用。

4.连接 DB

以 MySQL 为例,建立数据库连接。

import (
	"fmt"

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

// MySQLConn GORM MySQL 连接。
var MySQLConn *gorm.DB

// Init gorm mysql connnection.
// 依赖服务配置初始化完成。
func InitMySQLConn() error {
	// data source name.
	dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", Conf.Mysql.User, Conf.Mysql.Passwd, Conf.Mysql.IP, Conf.Mysql.Port, Conf.Mysql.Dbname)
	var err error
	MySQLConn, err = gorm.Open(mysql.Open(dsn))
	return err
}

填入 DB 对应的正确的用户名、密码、地址、端口、数据库名称等信息后,便可建立对应数据源的连接。相关配置一般在服务启动时,事先从配置文件中加载。

5.创建数据表

在进行增查改删(CRUD)之前,需要先创建一个数据表。

GORM 中一个 struct 对应一张数据库表,对应的 struct 被称为模型。

假如我们要创建一张商品(goods)表,那么 struct 可定义为:

// Good 商品。
type Good struct {
	gorm.Model
	Name  string `gorm:"type:varchar(255) not null"`
	Price int    `gorm:"type:bigint not null"`
}

其中 gorm.Model 时 GORM 预先定义的一些基础字段,我们可以嵌入直接拿来用。

// Model a basic GoLang struct which includes the following fields: ID, CreatedAt, UpdatedAt, DeletedAt
// It may be embedded into your model or you may build your own model without it
//
//	type User struct {
//	  gorm.Model
//	}
type Model struct {
	ID        uint `gorm:"primarykey"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt DeletedAt `gorm:"index"`
}

字段后的 tag 用来定义字段在 DB 中的相关属性,如 primarykey 表示主键,index 表示索引,type 表示字段类型。

除此以外,还有更加丰富的标签定义参见官方文档:字段标签。

一般在服务启动时创建数据表,如建立 DB 连接后只执行一次来完成数据表的创建。

db.AutoMigrate(&User{})

db.AutoMigrate(&User{}, &Product{}, &Order{})

// 创建表时添加后缀
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

比如创建我们上面的商品表。

// 自动创建表,如果表已经存在不会有任何动作。
err := MySQLConn.AutoMigrate(&Good{})

创建好后的数据表名为 struct 名称的 snake_case 复数形式,字段名为 struct 字段的 sanke_case 形式。

创建好的表结构如下:

在这里插入图片描述

6.增加(Create)

// createGood 插入商品。
func createGood(name string, price int) {
	task := &Good{
		Name:   name,
		Price: price,
	}
	result := MySQLConn.Create(task)
	if result.Error != nil {
		return 
	}
	return nil
}

主键 ID 会自增,此外 GORM 还会自动维护 created_at、updated_ad 和 deleted_at 三个字段。

7.查询(Read)

比如按照主键查询。

// getGoodByID 根据主键检索。
func getGoodByID (id int) (Good, error) {
	var good Good
	result := MySQLConn.First(&good, id)
	return good, result.Error
}

如果查不到,将报 “not found error” 错误。

再如按照其他字段进行 and 查询。

// getGoods 根据商品信息分页拉取。
func getTaskTypesByInfo(name string, price int, last_id uint) ([]Good, error) {
	db := internal.MySQLConn
	if name != "" {
		db = db.Where("name = ?", req.TypeInfo.Name)
	}
	db = db.Where("price >= ?", price)
	
	// 按照每页大小 50 拉取商品。
	db.Where("id > ?", last_id).Order("id asc").Limit(50)

	var goods []Good
	result := db.Find(&goods)
	return goods, result.Error
}

还有很多查询方式,比如按照 struct、map 指定查询字段以及 or 和 not 条件等,具体请参考官方文档 GORM 查询。

8.更新(Update)

比如更新所有字段。

使用 Save 方法更新所有字段,即使是零值也会更新。

// 先根据 ID  查询。
db.First(&good, 1)

// 再修改值。
good.Name = "小米"

// 最后写回。
db.Save(&user)

再如更改单列。

// 条件更新
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

// User 的 ID 是 `111`
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

再如更改多列。

Updates 方法支持 struct 和 map[string]interface{} 参数。当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段。

// 根据 `struct` 更新属性,只会更新非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;

// 根据 `map` 更新属性
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

9.删除(Delete)

如删除一条记录。

删除一条记录时,删除对象需要指定主键,否则会触发 批量 Delete,例如:

// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

再如根据主键删除。

GORM 允许通过主键(可以是复合主键)和内联条件来删除对象,它可以使用数字,也可以使用字符串。

db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;

db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;

db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);

注意:

如果您的模型包含了一个 gorm.DeletedAt 字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!

如果您不想引入 gorm.Model,您也可以这样启用软删除特性:

type User struct {
  ID      int
  Deleted gorm.DeletedAt
  Name    string
}

拥有软删除能力的模型调用 Delete 时,记录不会被数据库。但 GORM 会将 DeletedAt 置为当前时间, 并且你不能再通过普通的查询方法找到该记录。

使用 Unscoped 方法查找被软删除的数据。

db.Unscoped().Where("user_name = gry").Find(&users)

要想物理删除,使用 Unscoped 方法永久删除数据。

user.ID = 14
db.Unscoped().Delete(&user)

10.小结

本文简单介绍了 ORM、GORM、以及 GORM 连接数据库,创建数据表和 CRUD 的简单操作,帮忙新手快速上手。

更多用法,请参见官方文档 GORM 指南,这里有你想要的一切。


参考文献

GORM 指南| GORM - GORM
GORM 极速入门- 卢振千的博客
19-Gorm入门到精通- 刘清政 - 博客园
Go组件学习——gorm四步带你搞定DB增删改查 - 掘金

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

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

相关文章

Linux文件压缩和解压命令【gzip、gunzip、zip、unzip、tar】【详细总结】

解压和压缩gzip/gunzipgzip 压缩文件gunzip 解压缩文件zip/unzipzip命令语法命令选项实例unzip语法:命令选项实例tar语法实例例一:将文件打包成tar包例二:查阅 tar包内有哪些文件例三:将tar 包解压gzip/gunzip gzip用于解压文件&…

纵目科技冲刺科创板上市:拟募资20亿元,股东阵容强大

11月23日,纵目科技(上海)股份有限公司(下称“纵目科技”)在上海证券交易所递交招股书,准备在科创板上市。本次冲刺上市,纵目科技计划募资20亿元,拟用于上海研发中心建设项目、东阳智…

Redis常用指令汇总

文章目录一、5种数据类型二、常用指令汇总三、应用汇总提示:以下是本篇文章正文内容,Redis系列学习将会持续更新 一、5种数据类型 Redis 数据存储格式:  ● redis 自身是一个 Map ,其中所有的数据都是采用 key : value 的形式存储。  ● 数…

【c++】 继承的相关问题

继承无论是那种继承方式,基类继承的私有属性都无法访问不论父类中的属性被啥修饰,都会被子类全盘接收public,protected,private继承private 继承和protected 继承都是类中可以访问,类外无法访问,这有什么区别呐?继承的…

区间信息维护与查询【最近公共祖先LCA 】 - 原理

区间信息维护与查询【最近公共祖先LCA 】 - 原理 最近公共祖先(Lowest Common Ancestors,LCA)指有根树中距离两个节点最近的公共祖先。 祖先指从当前节点到树根路径上的所有节点。 u 和v 的公共祖先指一个节点既是u 的祖先,又是…

React基础之Context

前文有讲到Vue中的provide透传,祖孙组件之间通信。在react中也有类似的存在,他就是context,context的作用也是让祖孙组件之前通信。 React中,通过createContext方法来创建一个Context对象。 import React, { createContext } fr…

sqli-labs/Less-51

这一关的欢迎界面依然是以sort作为注入点 我们首先来判断一下是否为数字型注入 输入如下 sortrand() 对尝试几次 发现页面并没有发生变化 说明这道题的注入类型属于字符型 然后尝试输入以下内容 sort1 报错了 报错信息如下 我们从报错信息可以知道这道题的注入类型属于单…

JS-基础

JavaScript 基础第一天 01 JavaScript介绍 1.1 JavaScript 注释 单行注释 符号://作用://右边这一行的代码会被忽略快捷键:ctrl / 块注释 符号:/* */作用:在/* 和 */ 之间的所有内容都会被忽略快捷键:s…

【附源码】计算机毕业设计JAVA移动在线点菜系统服务端服务端

【附源码】计算机毕业设计JAVA移动在线点菜系统服务端服务端 目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术&#xff1…

【Unity】TimeLine系列教程——编排剧情!

前言 我们经常会看到游戏中有很多“花里胡哨”的系统,比如这样: 火影忍着疾风传 碧之轨迹S技能 这种效果感觉上像播放视频一样,但是却能将游戏不同的敌人加到镜头里面,有时候甚至根据双方关系还会有不同的反馈。如果是做视频或…

基于DQN的强化学习 快速浏览(基础知识+示例代码)

一、强化学习的基础概念 强化学习中有2个主要的实体,一个是智能体(agent),另一个是环境(environment)。在强化学习过程中,智能体能够得到的是环境当前的状态(State),即环境智能体所处环境当前的情况。另一个是上一步获得的环境的…

NePTuNe 论文笔记

NePTuNe:Neural Powered Tucker Network for Knowledge Graph Completion- Introduction- Background- Algorithm- Experiment- Conclusion- CodeShashank Sonkar, Arzoo Katiyar, Richard G.Baraniuk - Introduction 目前的链接预测方法: 张量因式分解&#xff1…

【服务器数据恢复】raidz多块硬盘离线的数据恢复案例

服务器数据恢复环境: 一台采用zfs文件系统的服务器,配备32块硬盘。 服务器故障: 服务器在运行过程中崩溃,经过初步检测没有发现服务器有物理故障,重启服务器后故障依旧,用户联系我们中心要求恢复服务器数据…

SpringBoot: Controller层的优雅实现

目录1. 实现目标2. 统一状态码3. 统一响应体4. 统一异常5. 统一入参校验6. 统一返回结果7. 统一异常处理8. 验证1. 实现目标 优雅校验接口入参响应体格式统一处理异常统一处理 2. 统一状态码 创建状态码接口,所有状态码必须实现这个接口,统一标准 pa…

Eolink 征文活动- -专为开发者设计的一款国产免费 API 协作平台

💗wei_shuo的个人主页 💫wei_shuo的学习社区 🌐Hello World ! ▌背景 后端开发的程序员都需要有一个用得顺手的接口测试工具;以前,大家都喜欢用Google开发的一款接口测试工具postman来进行测试,…

Java面向对象三大基本特征之多态

多态性是面向对象编程的又一个重要特征,那么多态是什么呢? 一、多态的概念 1.概念:多态是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各…

Linux 文件操作(一) —— 遍历指定目录下的所有文件

目录 一、访问目录相关函数 1、打开/访问目录 (opendir / fdopendir) 2、读取目录内容 (readdir) 3、关闭目录 (closedir) 二、遍历指定目录下的所有文件 一、访问目录相关函数 1、打开/访问目录 (opendir / fdopendir) opendir / fdopendir 函数的作用是访问指定路径的…

工程基建--前端基建

序: 工程基建 : 编码规范、api规范、前后端协作、环境部署、微服务、微前端、性能、安全防御、统计监控、可视化 等等的建设; 后端基建: 后端规范文档、后端模板、安全、日志、微服务、RESTful API、中间件、数据库、分布式、权…

新手怎么做微信商城小程序_微信商城小程序模版哪里找

微信小程序已经在我们的生活中随处可见,甚至是抖音头条等其它的平台也开始做起了小程序,在这种情况下,微信小程序势必会成为未来商城的主战场之一。闻风而来想做小程序的人不少,而其中新手零基础也能做的小程序商城模板类工具&…

C++入门教程2||C++ 数据类型

C 数据类型 使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。 您可能需要存储各种数据类型(比如字符型、宽字符型、整型…