GORM设计原理和实践(七)——GORM

news2024/9/24 13:16:06

文章目录

    • 一、重点内容:
        • 1、GROM设计原理
        • 2、GROM配置
        • 3、GROM使用即CRUD
    • 二、详细知识点介绍:
      • 1、GORM设计原理图
      • 2、SQL是怎么生成的
      • 3、GROM配置
        • 开启go model
        • 设置go model
        • 输入代理:
        • 导入依赖:
      • 4、GROM操作初体验
        • 代码:
      • 5、模型定义:
        • 约定
        • go Model
        • 权限控制:
      • 6、数据库CRUD
        • 用指定的字段创建记录
        • 查询:
          • 检索单个对象:
          • 根据主键检索
          • 检索全部对象
          • 条件查询:
          • Not 条件
          • Or 条件
          • 选择特定字段
          • 排序
          • Limit & Offset
        • 更新
          • 保存所有字段
          • 更新单个列
          • 更新多列
          • 更新选定字段
        • 删除
          • 删除一条记录
          • 根据主键删除
    • 三、个人总结

一、重点内容:

1、GROM设计原理

2、GROM配置

3、GROM使用即CRUD

二、详细知识点介绍:

1、GORM设计原理图

image-20230211211145066

2、SQL是怎么生成的

SQL语句例子:

SELECT `name`, `age `, `employee_number'
FROM `users'
WHERE
`role` > "manager" AND `age` > 35
ORDER BY `age` DESC
LIMIT 10 OFFSET 10
FOR UPDATE

同含义GROM代码:

db.Where(" role <> ?", "manager").Where("age > ?"35).Limit(100).Order("age desc").Find(&user)

查看where接口api:

// [docs]: https://gorm.io/docs/query.html#Conditions
func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {
   tx = db.getInstance()
   if conds := tx.Statement.BuildCondition(query, args...); len(conds) > 0 {
      tx.Statement.AddClause(clause.Where{Exprs: conds})
   }
   return
}

3、GROM配置

开启go model

# 开启go mod
go env -w GO111MODULE=on
# 这个命令会在当前目录创建一个名为go.mod的文件, 在本文中不会修改它的内容
go mod init huzhenwei.top/utils

设置go model

go env

找到:GOPROXY

image-20230212203331750

输入代理:

image-20230212203424546

导入依赖:

go get github.com/jinzhu/gorm
go get github.com/jinzhu/gorm/dialects/mysql

查看go.sum文件是否导入成功:

image-20230212203735482

4、GROM操作初体验

1、结构体映射建立数据库表

2、插入一条数据

代码:

package main

import (
   "fmt"
   "github.com/jinzhu/gorm"
   _ "github.com/jinzhu/gorm/dialects/mysql"
   "log"
   "time"
)

// Info  结构体名、变量名一定要使用大驼峰命名法(每个单词首字母大写)
type Info struct {
   gorm.Model
   Name string
}

func main() {
   db, err := gorm.Open("mysql", "root:XXXXXXX@tcp(127.0.0.1:3306)/mybatis?charset=utf8mb4&parseTime=True&loc=Local")
   if err != nil {
      log.Print(err)
   }
   // 结构体映射成为数据库表
   migrate := db.AutoMigrate(&Info{})
   if migrate.Error != nil {
      fmt.Println(migrate.Error)
   }
   model := gorm.Model{
      CreatedAt: time.Time{},
      UpdatedAt: time.Time{},
      DeletedAt: nil,
   }
   info := Info{model, "小黄"}
   // 插入数据
   db.Create(&info)
   fmt.Println("ok")
   // 关闭数据库连接
   defer func(db *gorm.DB) {
      err := db.Close()
      if err != nil {
         log.Println(err)
      }
   }(db)
}

测试:

image-20230212204240118

5、模型定义:

模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成

例如:

type User struct {
  ID           uint
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivatedAt  sql.NullTime
  CreatedAt    time.Time
  UpdatedAt    time.Time
}

约定

GORM 倾向于约定优于配置 默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAtUpdatedAt 字段追踪创建、更新时间

如果您遵循 GORM 的约定,您就可以少写的配置、代码。 如果约定不符合您的实际要求,GORM 允许你配置它们

go Model

GORM 定义一个 gorm.Model 结构体,其包括字段 IDCreatedAtUpdatedAtDeletedAt

image-20230212205413295

你可以将go Model直接在结构体中使用:

type Info struct {
   gorm.Model
   Name string
}

权限控制:

可导出的字段在使用 GORM 进行 CRUD 时拥有全部的权限,此外,GORM 允许您用标签控制字段级别的权限。这样您就可以让一个字段的权限是只读、只写、只创建、只更新或者被忽略

type User struct {
   Name string `gorm:"<-:create"` // 允许读和创建
   Name string `gorm:"<-:update"` // 允许读和更新
   Name string `gorm:"<-"`        // 允许读和写(创建和更新)
   Name string `gorm:"<-:false"`  // 允许读,禁止写
   Name string `gorm:"->"`        // 只读(除非有自定义配置,否则禁止写)
   Name string `gorm:"->;<-:create"` // 允许读和写
   Name string `gorm:"->:false;<-:create"` // 仅创建(禁止从 db 读)
   Name string `gorm:"-"`  // 通过 struct 读写会忽略该字段
   Name string `gorm:"-:all"`        // 通过 struct 读写、迁移会忽略该字段
   Name string `gorm:"-:migration"`  // 通过 struct 迁移会忽略该字段
}

6、数据库CRUD

用指定的字段创建记录

创建记录并更新给出的字段。

db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建一个记录且一同忽略传递给略去的字段值。

db.Omit("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

查询:

检索单个对象:
// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;

// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;

// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;

result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error        // returns error or nil

// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)
根据主键检索
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;

db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;

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

当目标对象有一个主键值时,将使用主键构建查询条件,例如:

var user = User{ID: 10}
db.First(&user)
// SELECT * FROM users WHERE id = 10;

var result User
db.Model(User{ID: 10}).First(&result)
// SELECT * FROM users WHERE id = 10;
检索全部对象
// Get all records
result := db.Find(&users)
// SELECT * FROM users;

result.RowsAffected // returns found records count, equals `len(users)`
result.Error        // returns error
条件查询:
// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;

// Get all matched records
db.Where("name <> ?", "jinzhu").Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';

// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');

// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';

// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;

// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';

// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
Not 条件
db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;

// Not In
db.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&users)
// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");

// Struct
db.Not(User{Name: "jinzhu", Age: 18}).First(&user)
// SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1;

// Not In slice of primary keys
db.Not([]int64{1,2,3}).First(&user)
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;
Or 条件
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';

// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);
选择特定字段
db.Select("name", "age").Find(&users)
// SELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
// SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,'42') FROM users;
排序
db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

// Multiple orders
db.Order("age desc").Order("name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

db.Clauses(clause.OrderBy{
  Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
}).Find(&User{})
// SELECT * FROM users ORDER BY FIELD(id,1,2,3)
Limit & Offset
db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;

// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)

db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;

db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;

// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)

更新

保存所有字段

注:以下user的ID:111`

Save 会保存所有的字段,即使字段是零值

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
更新单个列

当使用 Update 更新单列时,需要有一些条件,否则将会引起错误 ErrMissingWhereClause ,查看 阻止全局更新 了解详情。 当使用 Model 方法,并且值中有主键值时,主键将会被用于构建条件,例如:

// 条件更新
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 方法支持 structmap[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;

注意 当使用 struct 进行更新时,GORM 只会更新非零值的字段。 你可以使用 map 更新字段,或者使用 Select 指定要更新的字段

更新选定字段

如果您想要在更新时选定、忽略某些字段,您可以使用 SelectOmit

// Select with Map
// User's ID is `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;

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

// Select with Struct (select zero value fields)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;

// Select all fields (select all fields include zero value fields)
db.Model(&user).Select("*").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})

// Select all fields but omit Role (select all fields include zero value fields)
db.Model(&user).Select("*").Omit("Role").Updates(User{Name: "jinzhu", Role: "admin", Age: 0})

删除

删除一条记录

删除一条记录时,删除对象需要指定主键,否则会触发 批量 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);

三、个人总结

​ 本次学习内容较多,深入浅出了解使用了GROM,从开始的配置到后来对数据库的CRUD。其中GROM提供了通过结构体映射创建数据库表的方法释放友好,还有GROM通过的关键字对应接口使用十分方便,直接省去了复杂SQL语句的编写

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

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

相关文章

【Shell1】shell语法,ssh/build/scp/upgrade,环境变量,自动升级bmc

文章目录1.shell语法&#xff1a;shell是用C语言编写的程序&#xff0c;是用户使用Linux的桥梁&#xff0c;硬件>内核(os)>shell>文件系统1.1 变量&#xff1a;readonly定义只读变量&#xff0c;unset删除变量1.2 函数&#xff1a;shell脚本传递的参数中包含空格&…

app逆向篇之安卓模拟器环境搭建

前言 本教程适配:安卓7以上的安卓模拟器(包括雷电9等安卓9的模拟器&#xff09; 准备工具 雷电模拟器面具debug版LSPosed 正式步骤 安装雷电模拟器&#xff0c;这里怎么安装就不需要说了吧安装好雷电模拟器之后应该能够在桌面上看到两个图标&#xff0c;如下&#xff1a; …

分页和mmap

文章目录一、内存分页1、基本概念2、分页机制下&#xff0c;虚拟地址和物理地址是如何映射的&#xff1f;3、快表(TLB)二、mmap基本原理和分类一、内存分页 1、基本概念 CPU并不是直接访问物理内存地址&#xff0c;而是通过虚拟地址空间来间接的访问物理内存地址。 页&#x…

CSS ~ 从入门到入坑。

CSS ~ 从入门到入坑。 文章目录CSS ~ 从入门到入坑。what。css 三种实现方式。选择器。id 选择器 > class 选择器 > 标签选择器。标签选择器。类选择器。id 选择器。层次选择器。后代选择器。子选择器。相邻兄弟选择器。通用选择器。结构伪类选择器。属性选择器。字体风格…

OpenAI ChatGPT模型训练

打开VSCode 新建一个工作目录 使用pip install --upgrade openai 配置环境变量&#xff1a; OPENAI_API_KEY<你的open ai key> windows配置:(需要重启) setx OPENAI_API_KEY "你的open ai key" 准备训练数据集文件&#xff1a; 格式如下&#xff1a; 放到工作目…

NSSROUND#8[Basic]

文章目录一、[NSSRound#8 Basic]MyDoor二、[NSSRound#8 Basic]Upload_gogoggo三、[NSSRound#8 Basic]MyPage四、[NSSRound#8 Basic]ez_node一、[NSSRound#8 Basic]MyDoor <?php error_reporting(0);if (isset($_GET[N_S.S])) {eval($_GET[N_S.S]); }if(!isset($_GET[file])…

如何备考系统集成项目管理工程师?

首先了解考试信息&#xff0c;做好备考计划&#xff0c;准备好备考资料等~现在网上也有很多的视频教程&#xff0c;跟着一起学习&#xff0c;大概一周的时间就能过完。如果时间紧张&#xff0c;可以直接抓重点章节真题的复习。考试重点诺&#xff0c;重点章节标红了的&#xff…

NSACE高级WEB安全专家

目录信息收集基本信息收集域名注册信息收集子域名信息收集IP查询系统鉴定端口扫描搜索引擎信息收集 信息收集包括基本信息收集和搜索引擎收集 基本信息收集 基本信息收集方式如下&#xff1a; 域名注册信息查询&#xff1a;例如www.baidu.com 的注册信息&#xff0c;包含注…

vue3的核心知识点合集

Vue3 中文文档(新) Vue.js - 渐进式 JavaScript 框架 | Vue.js vue3的优点&#xff1a; 首次渲染更快diff 算法更快内存占用更少打包体积更小更好的 Typescript 支持Composition API 组合 API首先理解一下vite 构建工具&#xff1a; vite是一种新型前端构建工具&#xff0c;…

解答vue组件中一级组件可不可以作二级组件这个疑惑

引子 大家请看如下情况&#xff0c;我需要做一个项目&#xff0c;首页上的“产品介绍”部分同样也是导航导向的一部分&#xff1a; 首页中的部分&#xff1a; 导航栏导向的部分&#xff1a; 这里我要表达的是&#xff0c;组件Case在导航栏中属于一级路由&#xff0c;而在首…

解决idea出现的java.lang.OutOfMemoryError: Java heap space的问题

文章目录1. 复现问题2. 分析问题3. 解决问题4. 补充解决java.lang.OutOfMemoryError: PermGen space问题1. 复现问题 今天使用idea开发时&#xff0c;突然报出如下错误&#xff1a; Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat org.…

【测试开发】web 自动化测试 --- selenium4

目录1. 什么是自动化为什么要做自动化2. 为什么选择selenium作为我使用的web自动化工具3. 什么是驱动&#xff1f;驱动的工作原理是什么5. 第一个自动化程序演示6. selenium基本语法6.1 定位元素的方法6.2 操作页面元素6.3 等待6.4 信息打印获取当前页面句柄&#xff0c;窗口切…

vue脚手架安装详细

一、vue脚手架安装命令npm i -g vue/cli 或 yarn global add vue/cli安装上面的工具&#xff0c;安装后运行 vue --version &#xff0c;如果看到版本号&#xff0c;说明安装成功或 vue -V工具安装好之后&#xff0c;就可以安装带有webpack配置的vue项目了。创建项目之前&#…

基于java的学生成绩管理系统 完整代码 毕业设计

完整项目代码&#xff1a;https://download.csdn.net/download/qq_38735017/87382417下面是程序界面的详情&#xff1a;分享不易 谢谢&#xff01;主界面首先是开始界面&#xff0c;功能选择窗口&#xff0c;包含 5 个功能按钮清除数据功能清空数据库数据&#xff08;若出现 bu…

问题状态(Conditioning of a problem)

Conditioning of a problem该博客是学习《Numerical Linear Algebra with Applications Using MATLAB》的一些总结&#xff0c;仅供学习使用。 通常即使使用一个稳定的算法来解决一个问题&#xff0c;该问题对数据中小的改变或扰动仍然是敏感的。这些扰动可能来自舍入误差(roun…

Python与Arcgis 获取图像信息

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里实现一个很简单的功能,批量的获取图像的相关信息,如影像格式、y分辨率等等,并将这些信息写入到一个csv文件中,同时也会为每个图像生成相应的矩形掩模面。 二、实现代码 在真正执行代码之前,我们首先配置一…

PAT——1111 对称日

央视新闻发了一条微博&#xff0c;指出 2020 年有个罕见的“对称日”&#xff0c;即 2020 年 2 月 2 日&#xff0c;按照 年年年年月月日日 格式组成的字符串 20200202 是完全对称的。 给定任意一个日期&#xff0c;本题就请你写程序判断一下&#xff0c;这是不是一个对称日&a…

DDD 参考工程架构

1 背景 不同团队落地DDD所采取的应用架构风格可能不同&#xff0c;并没有统一的、标准的DDD工程架构。有些团队可能遵循经典的DDD四层架构&#xff0c;或改进的DDD四层架构&#xff0c;有些团队可能综合考虑分层架构、整洁架构、六边形架构等多种架构风格&#xff0c;有些在实…

【JUC并发编程】ArrayBlockingQueue和LinkedBlockingQueue源码2分钟看完

文章目录1、BlockingQueue1&#xff09;接口方法2&#xff09;阻塞队列分类2、ArrayBlockingQueue1&#xff09;构造函数2&#xff09;put()入队3&#xff09;take()出队3、LinkedBlockingQueue1&#xff09;构造函数2&#xff09;put()入队3&#xff09;take()出队1、Blocking…

Android Dalvik虚拟机 对象创建内存分配流程

前言 本篇文章介绍我们在日常开发使用Java时new对象的时&#xff0c;Dalvik在堆上的内存分配是如何分配的。内存又和gc相关&#xff0c;下篇文章会分析Dalvik的gc流程。 Dalvik内存管理 内存碎片问题其实是一个通用的问题&#xff0c;不单止Dalvik虚拟机在Java堆为对象分配内…