探索Gorm - Golang流行的数据库ORM框架

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 探索Gorm - Golang流行的数据库ORM框架

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站https://www.captainbed.cn/kitie。


前言

我们在之前的专栏中讲解了在Go中如何使用原生的database/sql库完成数据库编程,今天我们继续来了解一下一款在go中常用的数据库ORM框架-Gorm(GORM - The fantastic ORM library for Golang, aims to be developer friendly.)


ORM(Object-Relational Mapping)是一种编程技术,它将对象和关系数据库之间的映射抽象出来,使得开发者可以通过面向对象的方式操作数据库,而不用直接处理SQL语句,相当于在业务逻辑层和数据库层之间一座桥梁。


Gorm是一款用于Golang的ORM框架,它提供了丰富的功能,包括模型定义、数据验证、关联查询等。 Gorm的设计目标是简洁而强大,使得开发者能够更轻松地进行数据库操作

1.安装与配置

安装gorm库
go get -u gorm.io/gorm


安装mysql驱动
go get -u gorm.io/driver/mysql


连接url的组成
[DRIVER]://[USER]:[PASS]@[IP]:[PORT]/[DBNAME]?charset=utf8&parseTime=True&loc=Local


DRIVER: 数据库驱动名称,如mysql,postgres,sqlite3等


USER: 数据库用户名


PASS: 数据库密码


IP: 数据库主机IP地址,可以是localhost或127.0.0.1等


PORT: 数据库端口,默认为3306


DBNAME: 数据库名称


charset: 字符集,默认utf8


parseTime: 是否解析时间字段,默认True


loc: 时区,默认Local示例(mysql连接url)

mysql://root:123123@tcp(127.0.0.1:3306)/testName?charset=utf8mb4&parseTime=True&loc=Local

2.建立连接

自定义mysql配置
mysqlConfig := mysql.Config{
    DSN:                       dsn,   // 连接url
    DefaultStringSize:         255,   // string 类型字段的默认长度
    DisableDatetimePrecision:  true,  // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
    DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
    DontSupportRenameColumn:   true,  // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
    SkipInitializeWithVersion: false, // 根据版本自动配置
}


自定义gorm配置
gormConfig := &gorm.Config{
    DisableForeignKeyConstraintWhenMigrating: true,
    // 使用自定义的logger,gorm默认是将日志输出控制台,使用自定义logger可保存日志到文件
    Logger:                                   getGormLogger(), 
}
调用open对象建立连接,获取连接客户端
if db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig); err != nil {
    global.App.Log.Error("mysql connect failed, err:", zap.Any("err", err))
    return nil
  } else {
    global.App.Log.Info("mysql数据库连接成功~~~~~")
    sqlDB, _ := db.DB()
    sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns)
    sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns)
    //数据库表结构同步
    initMySqlTables(db)
    return db
  }
扩展:使用AutoMigrate进行表结构同步(根据定义的结构体创建/修改表结构,保证数据结构的一致性,省去手动建表的步骤)
/*
数据库表结构同步,该方法只会增加新的字段或修改字段,不会删除字段,
AutoMigrate 方法会尝试自动更改表结构,以使其与结构体定义保持一致
*/
func initMySqlTables(db *gorm.DB) {
    err := db.AutoMigrate(
       // 需要同步的表的结构体放里面
       model.User{},
       model.Media{},
    )
    if err != nil {
       global.App.Log.Error("migrate table failed", zap.Any("err", err))
       // 退出程序
       os.Exit(0)
    }
}

3.基本使用

添加

Create()

添加一条数据,不能重复添加

user := User{Name: "jinzhu"}
db.Create(&user) 
user := User{Name: "jinzhu"}
db.Model(&user).Create(&user)
Save()

添加一条数据,若已存在,则更新对应数据

user := User{Name: "jinzhu"}
db.Save(&user) 


CreateInBatches(records, batchSize)

批量添加数据


  • records:要插入的记录的切片或结构体
  • batchSize:每个批量添加的数量,避免一次性插入太多记录对数据库造成压力
users := []User{
  {Name: "jinzhu"},
  {Name: "hello"},
} 
db.CreateInBatches(users, 10)

删除

Delete()

根据结构体Id删除一条数据,若定义了DeletedAt字段,则会进行软删除

db.Delete(&user)
db.Model(&user).Delete(&User{})
.Unscoped().Delete()

忽略软删除直接删除一条数据

db.Unscoped().Delete(&user)
Where().Delete()

根据条件删除多条记录

db.Where("name = ?", "jinzhu").Delete(&User{})


修改

db.Save()

根据结构体主键更新数据

user.Name = "updated"
db.Save(&user) 
db.Model().Update()

通过模型对象更新指定字段

db.Model(&user).Update("name", "new_name")


db.Updates()

批量更新结构体中的字段

db.Model(&user).Updates(User{Name: "new"})
db.UpdateColumn()

更新单个字段

db.Model(&user).UpdateColumn("name", "new")
db.Where().Update()

根据条件更新多条记录

db.Where("id=?", 1).Update("name", "updated")

查询

db.First()

查询第一条记录

1. var user User
2. db.First(&user, 1) // id = 1


db.Where().Find()

条件查询多条记录

db.Where("name = ?", "jinzhu").Find(&users)


db.Order()

排序查询

db.Order("age desc").Find(&users)


db.Limit()

限制返回条数

db.Limit(10).Find(&users)
db.Offset()

分页查询

db.Offset(20).Limit(10).Find(&users)
db.Count()

统计记录数

1. var count int
2. db.Find(&users).Count(&count)

事务

tx := db.Begin() //开启事务
tx.Create(&user)
tx.Commit() //提交事务
tx.Rollback() //回滚事务


4.其他常用方法

Preload():预加载

目的:减少sql查询次数,避免N+1问题,减少内存开销,适用于复杂关系
基本使用:

结构体定义:gorm:"foreignKey:problem_id;references:id"指明关联关系,gorm会根据该关系进行预加载。如下面例子中把Struct111的problem_id与ProblemBasic的id关联起来。

// 要使用预加载函数的结构体
type ProblemBasic struct {
    ID                uint               `gorm:"primarykey;" json:"id"`
    
    //  需要预加载的数据
    Struct1 []*Struct111 `gorm:"foreignKey:problem_id;references:id" json:"problem_categories"` 
    Struct2 *Struct2222 `gorm:"foreignKey:problem_id;references:id;" json:"test_cases"`             
}

使用预加载函数:

err = tx.Preload("Struct1").Preload("Struct2").Find(&problemList).Error

预加载中省略某字段:

err = tx.Preload("Struct1", func(db *gorm.DB) *gorm.DB {
    return db.Omit("省略的字段名")
}).Preload("Struct2").Find(&problemList).Error


Omit():查询中省略指定字段

tx := DB.Model(&model.ProblemBasic{}).Omit("content")

5.格式化时间字段

当我们使用gorm时,往往需要格式化时间字段来满足使用需求

自定义时间类型,重写其方法

type LocalTime time.Time
 
// 定义 LocalTime 类型在 JSON 编码时的行为
func (t *LocalTime) MarshalJSON() ([]byte, error) {
  tTime := time.Time(*t)
  return []byte(fmt.Sprintf("\"%v\"", tTime.Format("2006-01-02 15:04:05"))), nil
}
 
// Value方法即在存储时调用,将该方法的返回值进行存储,该方法可以实现数据存储前对数据进行相关操作
func (t LocalTime) Value() (driver.Value, error) {
    var zeroTime time.Time
    tlt := time.Time(t)
    //判断给定时间是否和默认零时间的时间戳相同
    if tlt.UnixNano() == zeroTime.UnixNano() {
      return nil, nil
    }
    return tlt, nil
}
 
// Scan方法可以实现在数据查询出来之前对数据进行相关操作
func (t *LocalTime) Scan(v interface{}) error {
    if value, ok := v.(time.Time); ok {
      *t = LocalTime(value)
      return nil
    }
    return fmt.Errorf("can not convert %v to timestamp", v)
}
 
 


总结

Gorm是一款用于Golang的ORM框架,它提供了丰富的功能,包括模型定义、数据验证、关联查询等。Go提供的原生库已经能够很好的完成数据库编程,而Gorm对其进行了封装,使得数据库操作变得更加简单和灵活。



相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
关系型数据库 MySQL 数据库
ORM对mysql数据库中数据进行操作报错解决
ORM对mysql数据库中数据进行操作报错解决
98 2
|
4月前
|
SQL 开发框架 数据库
".NET开发者的超能力:AgileEAS.NET ORM带你穿越数据库的迷宫,让数据操作变得轻松又神奇!"
【8月更文挑战第16天】AgileEAS.NET是面向.NET平台的企业应用开发框架,核心功能包括数据关系映射(ORM),允许以面向对象方式操作数据库,无需编写复杂SQL。通过继承`AgileEAS.Data.Entity`创建实体类对应数据库表,利用ORM简化数据访问层编码。支持基本的CRUD操作及复杂查询如条件筛选、排序和分页,并可通过导航属性实现多表关联。此外,提供了事务管理功能确保数据一致性。AgileEAS.NET的ORM简化了数据库操作,提升了开发效率和代码可维护性。
58 5
|
25天前
|
SQL 定位技术 数据库
深入探索Django ORM:高效数据库操作的秘诀####
本文旨在为读者揭开Django ORM(对象关系映射)的神秘面纱,通过一系列生动的比喻和详实的案例,深入浅出地讲解其核心概念、工作原理及高级特性。我们将一起探讨如何利用Django ORM简化数据库交互,提升开发效率,同时确保数据的一致性和安全性。不同于传统的技术文档,本文将以故事化的形式,带领读者在轻松愉快的氛围中掌握Django ORM的精髓。 ####
|
3月前
|
存储 关系型数据库 MySQL
【阿里规约】阿里开发手册解读——数据库和ORM篇
从命名规范、建表规范、查询规范、索引规范、操作规范等角度出发,详细阐述MySQL数据库使用过程中所需要遵循的各种规范。
|
2月前
|
SQL Go 数据库
【速存】深入理解Django ORM:编写高效的数据库查询
【速存】深入理解Django ORM:编写高效的数据库查询
86 0
|
4月前
|
搜索推荐 前端开发 算法
基于用户画像及协同过滤算法的音乐推荐系统,采用Django框架、bootstrap前端,MySQL数据库
本文介绍了一个基于用户画像和协同过滤算法的音乐推荐系统,使用Django框架、Bootstrap前端和MySQL数据库构建,旨在为用户提供个性化的音乐推荐服务,提高推荐准确性和用户满意度。
320 7
基于用户画像及协同过滤算法的音乐推荐系统,采用Django框架、bootstrap前端,MySQL数据库
|
4月前
|
SQL Java 数据库连接
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。通过映射机制,它可以自动处理对象与数据库表之间的转换,支持主流数据库,提高了代码的可移植性和可维护性。其核心接口包括 SessionFactory、Session 和 Transaction 等,通过它们可以执行数据库的 CRUD 操作。配置方面,需在项目中引入 Hibernate 及数据库驱动依赖,并创建 `hibernate.cfg.xml` 配置文件来设置数据库连接和 Hibernate 行为参数。
65 1
|
4月前
|
数据采集 前端开发 算法
基于朴素贝叶斯算法的新闻类型预测,django框架开发,前端bootstrap,有爬虫有数据库
本文介绍了一个基于Django框架和朴素贝叶斯算法开发的新闻类型预测系统,该系统具备用户登录注册、后台管理、数据展示、新闻分类分布分析、新闻数量排名和新闻标题预测等功能,旨在提高新闻处理效率和个性化推荐服务。
|
4月前
|
Java 数据库连接 数据库
告别繁琐 SQL!Hibernate 入门指南带你轻松玩转 ORM,解锁高效数据库操作新姿势
【8月更文挑战第31天】Hibernate 是一款流行的 Java 持久层框架,简化了对象关系映射(ORM)过程,使开发者能以面向对象的方式进行数据持久化操作而无需直接编写 SQL 语句。本文提供 Hibernate 入门指南,介绍核心概念及示例代码,涵盖依赖引入、配置文件设置、实体类定义、工具类构建及基本 CRUD 操作。通过学习,你将掌握使用 Hibernate 简化数据持久化的技巧,为实际项目应用打下基础。
341 0