Go 对象关系映射框架 GORM 使用示例

本贴最后更新于 1538 天前,其中的信息可能已经水流花落

前提条件

  • 安装 PostgreSql,创建好数据库(GORM 自动迁移表结构)
  • 安装 GoLandGo SDK
  • 获取 GORM:go get -u gorm.io/gorm
  • 获取 Postgres 驱动:go get -u gorm.io/driver/postgres

使用说明

  1. 复制本代码,打开 GoLand
  2. Ctrl + Shift + Alt + Insert 创建草稿文件
  3. 将代码粘贴到草稿文件中,修改数据库连接地址,按 Ctrl + Shift + F10 运行代码查看效果
package main import ( "database/sql" "encoding/json" "errors" "fmt" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" "gorm.io/gorm/schema" "log" "os" "strconv" "time" ) // 系统参数表结构体(实体类),GORM 约定参考: https://gorm.io/zh_CN/docs/conventions.html type TSysParam struct { // gorm.Model ID string `gorm:"type:varchar(32);not null;primaryKey;<-:create;comment:流水号参数唯一 ID"` DataTableName string `gorm:"type:varchar(128);<-;comment:数据库表名,如“t_sys_user”"` DataTableDescription string `gorm:"type:varchar(255);<-;comment:数据库表名(中文)说明信息"` SerialValue int `gorm:"size:32;<-;comment:流水号当前最大值"` SerialLength int `gorm:"size:32;<-;comment:流水号长度,不足前缀以“0”补齐"` Remark string `gorm:"type:varchar(1024);<-;comment:备注信息"` Enabled bool `gorm:"<-;default:true;comment:是否可用"` CreateTime *time.Time `gorm:"type:timestamptz;<-:create;autoCreateTime:milli;comment:创建时间"` CreateBy string `gorm:"type:varchar(32);<-:create;comment:创建人 ID,t_sys_user.id"` LastUpdateTime *time.Time `gorm:"type:timestamptz;<-;comment:最后修改时间"` LastUpdateBy string `gorm:"type:varchar(32);<-;comment:最后修改人 ID,t_sys_user.id"` } // 为 TSysParam 结构体实现获取表名方法,单独设置 TSysParam 结构体的表名为 `t_sys_param`,未配置全局禁用复数表名时可使用此方法 //func (TSysParam) TableName() string { // return "t_sys_param" //} // GORM 参考文档: https://gorm.io/zh_CN/docs/ func main() { initDbConn() // CRUD 示例 createExample() readExample() updateExample() deleteExample() printStats() } // GORM 数据库定义 var GormDB *gorm.DB // 连接池数据库句柄 var SqlDB *sql.DB // 错误信息 var err error // 初始化数据库连接 func initDbConn() { GormDB, err = gorm.Open(postgres.New(postgres.Config{ // 通过一个现有的数据库连接来初始化,无需使用 DSN // Conn: SqlDB, // 数据源名称 DSN: "host=192.168.1.1 port=5432 user=test password=test dbname=db_test sslmode=disable TimeZone=Asia/Shanghai", // 禁用隐式预处理语句 PreferSimpleProtocol: true, }), &gorm.Config{ // 日志配置 Logger: getLogger(), // 自定义命名策略 NamingStrategy: schema.NamingStrategy{ // 全局使用单数表,禁止自动转换为复数形式表名 SingularTable: true, }, // 插入数据默认批处理大小 CreateBatchSize: 1000, }) if err != nil { panic("数据库连接失败!") } // 数据库连接池 SqlDB, err = GormDB.DB() if err != nil { panic("数据库连接池获取失败!") } // 设置空闲连接池中连接的最大数量 SqlDB.SetMaxIdleConns(10) // 设置打开数据库连接的最大数量 SqlDB.SetMaxOpenConns(1e3) // 设置连接可复用的最大时间 SqlDB.SetConnMaxLifetime(time.Hour) printStats() // 自动迁移给定模型为数据库表结构,未创建表或需要修改表结构的情况下可以启用 // _ = GormDB.AutoMigrate(&TSysParam{}) } // 获取当前时间指针 func nowTime() *time.Time { now := time.Now() return &now } // 添加数据,参考 https://gorm.io/zh_CN/docs/create.html func createExample() { // 添加单条数据 sysParam := TSysParam{ ID: "test_001", DataTableName: "test_table", DataTableDescription: "测试表", SerialValue: 0, SerialLength: 10, Enabled: true, CreateBy: "00000", CreateTime: nowTime(), } result := GormDB.Create(&sysParam) printData(&sysParam, result, "Create") // 向指定(Select)字段中保存数据,忽略未指定的字段(NULL) sysParam = TSysParam{ ID: "test_002", DataTableName: "test_table_002", DataTableDescription: "测试表", SerialValue: 0, SerialLength: 10, Enabled: true, CreateBy: "00000", } result = GormDB. Select("ID", "DataTableName", "DataTableDescription", "SerialValue", "SerialLength"). Create(&sysParam) printData(&sysParam, result, "Create") // 添加多条数据 dataSize := 3 sysParams := make([]TSysParam, dataSize) for i := 0; i < dataSize; i++ { index := strconv.Itoa(i) sysParams[i] = TSysParam{ ID: "test_list_" + index, DataTableName: "test_table_" + index, DataTableDescription: "测试表_" + index, SerialValue: 0, SerialLength: 10, Enabled: true, CreateBy: "00000", } } // 未配置全局 CreateBatchSize 参数的情况下,一次性批量保存全部数据 result = GormDB.Create(&sysParams) // 指定单次批量保存的条数分批保存,每循环到 batchSize 条保存一次直至全部完成,保存大量数据可用此方法分批保存 // result = GormDB.CreateInBatches(&sysParams, dataSize) printData(&sysParams, result, "Create", "(batch)") } // 查询数据,参考 https://gorm.io/zh_CN/docs/query.html https://gorm.io/zh_CN/docs/advanced_query.html func readExample() { var sysParam *TSysParam // 根据主键查询单条数据,默认根据主键正序排序 result := GormDB.First(&sysParam, "00001") printData(sysParam, result, "First") sysParam = nil // 根据自定义条件查询最后一条数据,默认根据主键倒序排序 result = GormDB.Last(&sysParam, "enabled = ?", false) printData(sysParam, result, "Last") sysParam = nil // 获取一条数据,未指定排序字段 result = GormDB.Take(&sysParam, "create_by = ?", "00000") printData(sysParam, result, "Take") sysParam = nil // 不使用结构体查询,直接使用表名 result = GormDB.Table("t_sys_param").First(&sysParam) printData(sysParam, result, "Table", "First") sysParam = nil // 查询全部 sysParams := new([]TSysParam) result = GormDB.Find(&sysParams, "enabled = ?", true) // 查询可用数据 // result = GormDB.Find(&sysParams, "enabled = ?", true) printData(&sysParams, result, "Find", "(all)") // 按 AND 条件查询多条 sysParams = new([]TSysParam) result = GormDB.Find(&sysParams, TSysParam{Enabled: true, CreateBy: "00000"}) // 不使用结构体,直接使用字段 Map // result = GormDB.Find(&sysParams, map[string]interface{}{"enabled": true, "create_by": "00000"}) printData(&sysParams, result, "Find", "(AND)") // 按 OR 条件查询多条 sysParams = new([]TSysParam) result = GormDB.Where("enabled", true).Or("create_by", "00000").Find(&sysParams) printData(&sysParams, result, "Find", "(OR)") // 按 IN 条件查询多条 sysParams = new([]TSysParam) result = GormDB.Find(&sysParams, "id IN ?", []string{"00001", "00002"}) printData(&sysParams, result, "Find", "(IN)") // 按 NOT 条件查询多条 sysParams = new([]TSysParam) result = GormDB.Not("serial_value", 0).Find(&sysParams) printData(&sysParams, result, "Find", "(NOT)") // 分页排序查询指定字段 sysParams = new([]TSysParam) allSysParams := new([]TSysParam) result = GormDB. // 每页 5 条,第二页 Offset(5).Limit(5). Order("serial_value DESC, id"). Select("data_table_name", "serial_value", "serial_length"). Find(&sysParams) printData(&sysParams, result, "Find", "(select-order-paging)") // 消除分页,获取全部 unpageResult := result.Offset(-1).Limit(-1).Find(&allSysParams) // 总条数 pagingResult.RowsAffected printData(&allSysParams, unpageResult, "Find", "(select-order-paging-all)") } // 修改数据,参考 https://gorm.io/zh_CN/docs/update.html func updateExample() { sysParam := TSysParam{ ID: "test_001", // 根据主键修改指定数据 DataTableName: "test_table_001", DataTableDescription: "测试表-001", SerialValue: 1, SerialLength: 10, Enabled: true, CreateTime: nowTime(), // CreateTime 和 CreateBy 已在标签中配置为可读、可创建、不可修改 CreateBy: "00001", LastUpdateTime: nowTime(), LastUpdateBy: "00000", } // 更新所有字段,包含零值 result := GormDB.Save(&sysParam). // 查询修改结果重新赋值给 sysParam Find(&sysParam) printData(&sysParam, result, "UPDATE", "Save") // 更新单个字段 result = GormDB.Model(&sysParam). Where("enabled", true). Update("serial_value", sysParam.SerialValue+1). Find(&sysParam) printData(&sysParam, result, "UPDATE", "Model", "WhereUpdate") // 更新多个字段,使用结构体只会更新非零值字段,要更新零值字段需要使用 Select 指定要修改的字段,或者直接使用 Select("*") 更新全部字段 sysParam = TSysParam{ ID: "test_001", // 根据主键修改指定数据 SerialValue: sysParam.SerialValue + 1, SerialLength: 10, Enabled: false, // false 为 GORM Model 结构体零值,不会修改此字段 LastUpdateTime: nowTime(), LastUpdateBy: "00000", } result = GormDB.Model(&sysParam). Where("enabled", true). Updates(&sysParam). Find(&sysParam) printData(&sysParam, result, "UPDATE", "Model", "Updates") // 使用 map 可修改零值字段 result = GormDB.Model(&sysParam). Updates(map[string]interface{}{"serial_value": sysParam.SerialValue + 1, "enabled": false}). Find(&sysParam) printData(&sysParam, result, "UPDATE", "Model", "UpdatesMap") // 使用 Omit 忽略更新指定字段 result = GormDB.Model(&sysParam). Omit("serial_value"). Updates(map[string]interface{}{"serial_value": sysParam.SerialValue + 1, "enabled": true}). Find(&sysParam) printData(&sysParam, result, "UPDATE", "Model", "UpdatesOmit") } // 删除数据,参考 https://gorm.io/zh_CN/docs/delete.html func deleteExample() { // !!! 注意,删除数据时如果未指定主键或其他条件,将会触发无条件的批量删除 sysParam := TSysParam{ ID: "test_002", // 主键 } // 根据主键删除指定数据 result := GormDB.Delete(&sysParam) sysParam = TSysParam{} result.Find(&sysParam) printData(&sysParam, result, "Delete") // 通过复合条件删除数据 result = GormDB.Where("id LIKE ? AND data_table_name LIKE ?", "test_%", "test_table_%"). Delete(&sysParam). Find(&sysParam) printData(&sysParam, result, "DeleteWhere") } // 获取 GORM 日志接口 func getLogger() logger.Interface { gormLogger := logger.New( // io writer log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Config{ // 慢 SQL 阈值 SlowThreshold: 3 * time.Second, // 日志级别 LogLevel: logger.Info, // 是否启用彩色打印 Colorful: true, }, ) return gormLogger } // 打印数据 func printData(sysParam interface{}, result *gorm.DB, morInfo ...interface{}) { jsonByte, _ := json.Marshal(&sysParam) result.Logger.Info(nil, string(jsonByte)) fmt.Println("条数:", result.RowsAffected, "\t错误信息:[", result.Error, "]\t是否为无记录错误:", errors.Is(result.Error, gorm.ErrRecordNotFound)) if len(morInfo) > 0 { fmt.Println(morInfo) } } // 打印数据库统计信息 func printStats() { dbStats := SqlDB.Stats() jsonByte, _ := json.Marshal(dbStats) fmt.Println(string(jsonByte)) /*fmt.Printf(` 空闲连接数: %d 使用中的连接数: %d 由于达到设置的空闲连接池的最大数量而关闭的连接数: %d 由于达到设置的连接可空闲的最长时间而关闭的连接数: %d 由于达到设置的可重用连接的最长时间而关闭的连接数: %d 数据库的最大打开连接数: %d 等待的连接总数: %d 等待新连接被阻止的总时间: %d`, dbStats.Idle, dbStats.InUse, dbStats.MaxIdleClosed, dbStats.MaxIdleTimeClosed, dbStats.MaxLifetimeClosed, dbStats.MaxOpenConnections, dbStats.WaitCount, dbStats.WaitDuration)*/ }
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    498 引用 • 1395 回帖 • 249 关注
  • GORM
    8 引用 • 19 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
iTanken
飘风不终朝,骤雨不终日。 成都

推荐标签 标签

  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    56 引用 • 85 回帖 • 1 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 659 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 554 关注
  • Hibernate

    Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,使得 Java 程序员可以随心所欲的使用对象编程思维来操纵数据库。

    39 引用 • 103 回帖 • 724 关注
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 760 关注
  • SVN

    SVN 是 Subversion 的简称,是一个开放源代码的版本控制系统,相较于 RCS、CVS,它采用了分支管理系统,它的设计目标就是取代 CVS。

    29 引用 • 98 回帖 • 692 关注
  • 反馈

    Communication channel for makers and users.

    126 引用 • 930 回帖 • 273 关注
  • 996
    13 引用 • 200 回帖 • 3 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 610 关注
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 176 关注
  • 生活

    生活是指人类生存过程中的各项活动的总和,范畴较广,一般指为幸福的意义而存在。生活实际上是对人生的一种诠释。生活包括人类在社会中与自己息息相关的日常活动和心理影射。

    230 引用 • 1454 回帖
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9632 引用 • 43799 回帖 • 95 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    267 引用 • 666 回帖
  • Excel
    31 引用 • 28 回帖
  • WebClipper

    Web Clipper 是一款浏览器剪藏扩展,它可以帮助你把网页内容剪藏到本地。

    3 引用 • 9 回帖 • 3 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 648 关注
  • 分享

    有什么新发现就分享给大家吧!

    248 引用 • 1794 回帖 • 3 关注
  • CodeMirror
    2 引用 • 17 回帖 • 161 关注
  • Oracle

    Oracle(甲骨文)公司,全称甲骨文股份有限公司(甲骨文软件系统有限公司),是全球最大的企业级软件公司,总部位于美国加利福尼亚州的红木滩。1989 年正式进入中国市场。2013 年,甲骨文已超越 IBM,成为继 Microsoft 后全球第二大软件公司。

    107 引用 • 127 回帖 • 341 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖 • 1 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖
  • Telegram

    Telegram 是一个非盈利性、基于云端的即时消息服务。它提供了支持各大操作系统平台的开源的客户端,也提供了很多强大的 APIs 给开发者创建自己的客户端和机器人。

    5 引用 • 35 回帖 • 2 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    948 引用 • 1460 回帖
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖 • 3 关注
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    22 引用 • 148 回帖 • 16 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖