前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go 对象关系映射框架 GORM 使用示例

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

作者头像
子兮子兮
发布2022-08-30 15:15:18
1.7K0
发布2022-08-30 15:15:18
举报
文章被收录于专栏:JavaGoRustJavaGoRust

前提条件

  • 安装 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 运行代码查看效果
代码语言:javascript
复制
  1package main
  2
  3import (
  4	"database/sql"
  5	"encoding/json"
  6	"errors"
  7	"fmt"
  8	"gorm.io/driver/postgres"
  9	"gorm.io/gorm"
 10	"gorm.io/gorm/logger"
 11	"gorm.io/gorm/schema"
 12	"log"
 13	"os"
 14	"strconv"
 15	"time"
 16)
 17
 18// 系统参数表结构体(实体类),GORM 约定参考: https://gorm.io/zh_CN/docs/conventions.html
 19type TSysParam struct {
 20	// gorm.Model
 21	ID                   string     `gorm:"type:varchar(32);not null;primaryKey;<-:create;comment:流水号参数唯一 ID"`
 22	DataTableName        string     `gorm:"type:varchar(128);<-;comment:数据库表名,如“t_sys_user”"`
 23	DataTableDescription string     `gorm:"type:varchar(255);<-;comment:数据库表名(中文)说明信息"`
 24	SerialValue          int        `gorm:"size:32;<-;comment:流水号当前最大值"`
 25	SerialLength         int        `gorm:"size:32;<-;comment:流水号长度,不足前缀以“0”补齐"`
 26	Remark               string     `gorm:"type:varchar(1024);<-;comment:备注信息"`
 27	Enabled              bool       `gorm:"<-;default:true;comment:是否可用"`
 28	CreateTime           *time.Time `gorm:"type:timestamptz;<-:create;autoCreateTime:milli;comment:创建时间"`
 29	CreateBy             string     `gorm:"type:varchar(32);<-:create;comment:创建人 ID,t_sys_user.id"`
 30	LastUpdateTime       *time.Time `gorm:"type:timestamptz;<-;comment:最后修改时间"`
 31	LastUpdateBy         string     `gorm:"type:varchar(32);<-;comment:最后修改人 ID,t_sys_user.id"`
 32}
 33
 34// 为 TSysParam 结构体实现获取表名方法,单独设置 TSysParam 结构体的表名为 `t_sys_param`,未配置全局禁用复数表名时可使用此方法
 35//func (TSysParam) TableName() string {
 36//	return "t_sys_param"
 37//}
 38
 39// GORM 参考文档: https://gorm.io/zh_CN/docs/
 40func main() {
 41	initDbConn()
 42
 43	// CRUD 示例
 44	createExample()
 45	readExample()
 46	updateExample()
 47	deleteExample()
 48
 49	printStats()
 50}
 51
 52// GORM 数据库定义
 53var GormDB *gorm.DB
 54
 55// 连接池数据库句柄
 56var SqlDB *sql.DB
 57
 58// 错误信息
 59var err error
 60
 61// 初始化数据库连接
 62func initDbConn() {
 63	GormDB, err = gorm.Open(postgres.New(postgres.Config{
 64		// 通过一个现有的数据库连接来初始化,无需使用 DSN
 65		// Conn: SqlDB,
 66		// 数据源名称
 67		DSN: "host=192.168.1.1 port=5432 user=test password=test dbname=db_test sslmode=disable TimeZone=Asia/Shanghai",
 68		// 禁用隐式预处理语句
 69		PreferSimpleProtocol: true,
 70	}), &gorm.Config{
 71		// 日志配置
 72		Logger: getLogger(),
 73		// 自定义命名策略
 74		NamingStrategy: schema.NamingStrategy{
 75			// 全局使用单数表,禁止自动转换为复数形式表名
 76			SingularTable: true,
 77		},
 78		// 插入数据默认批处理大小
 79		CreateBatchSize: 1000,
 80	})
 81	if err != nil {
 82		panic("数据库连接失败!")
 83	}
 84
 85	// 数据库连接池
 86	SqlDB, err = GormDB.DB()
 87	if err != nil {
 88		panic("数据库连接池获取失败!")
 89	}
 90	// 设置空闲连接池中连接的最大数量
 91	SqlDB.SetMaxIdleConns(10)
 92	// 设置打开数据库连接的最大数量
 93	SqlDB.SetMaxOpenConns(1e3)
 94	// 设置连接可复用的最大时间
 95	SqlDB.SetConnMaxLifetime(time.Hour)
 96	printStats()
 97
 98	// 自动迁移给定模型为数据库表结构,未创建表或需要修改表结构的情况下可以启用
 99	// _ = GormDB.AutoMigrate(&TSysParam{})
100}
101
102// 获取当前时间指针
103func nowTime() *time.Time {
104	now := time.Now()
105	return &now
106}
107
108// 添加数据,参考 https://gorm.io/zh_CN/docs/create.html
109func createExample() {
110	// 添加单条数据
111	sysParam := TSysParam{
112		ID:                   "test_001",
113		DataTableName:        "test_table",
114		DataTableDescription: "测试表",
115		SerialValue:          0,
116		SerialLength:         10,
117		Enabled:              true,
118		CreateBy:             "00000",
119		CreateTime:           nowTime(),
120	}
121
122	result := GormDB.Create(&sysParam)
123	printData(&sysParam, result, "Create")
124
125	// 向指定(Select)字段中保存数据,忽略未指定的字段(NULL)
126	sysParam = TSysParam{
127		ID:                   "test_002",
128		DataTableName:        "test_table_002",
129		DataTableDescription: "测试表",
130		SerialValue:          0,
131		SerialLength:         10,
132		Enabled:              true,
133		CreateBy:             "00000",
134	}
135	result = GormDB.
136		Select("ID", "DataTableName", "DataTableDescription", "SerialValue", "SerialLength").
137		Create(&sysParam)
138	printData(&sysParam, result, "Create")
139
140	// 添加多条数据
141	dataSize := 3
142	sysParams := make([]TSysParam, dataSize)
143	for i := 0; i < dataSize; i++ {
144		index := strconv.Itoa(i)
145		sysParams[i] = TSysParam{
146			ID:                   "test_list_" + index,
147			DataTableName:        "test_table_" + index,
148			DataTableDescription: "测试表_" + index,
149			SerialValue:          0,
150			SerialLength:         10,
151			Enabled:              true,
152			CreateBy:             "00000",
153		}
154	}
155	// 未配置全局 CreateBatchSize 参数的情况下,一次性批量保存全部数据
156	result = GormDB.Create(&sysParams)
157	// 指定单次批量保存的条数分批保存,每循环到 batchSize 条保存一次直至全部完成,保存大量数据可用此方法分批保存
158	// result = GormDB.CreateInBatches(&sysParams, dataSize)
159	printData(&sysParams, result, "Create", "(batch)")
160}
161
162// 查询数据,参考 https://gorm.io/zh_CN/docs/query.html  https://gorm.io/zh_CN/docs/advanced_query.html
163func readExample() {
164	var sysParam *TSysParam
165	// 根据主键查询单条数据,默认根据主键正序排序
166	result := GormDB.First(&sysParam, "00001")
167	printData(sysParam, result, "First")
168	sysParam = nil
169
170	// 根据自定义条件查询最后一条数据,默认根据主键倒序排序
171	result = GormDB.Last(&sysParam, "enabled = ?", false)
172	printData(sysParam, result, "Last")
173	sysParam = nil
174
175	// 获取一条数据,未指定排序字段
176	result = GormDB.Take(&sysParam, "create_by = ?", "00000")
177	printData(sysParam, result, "Take")
178	sysParam = nil
179
180	// 不使用结构体查询,直接使用表名
181	result = GormDB.Table("t_sys_param").First(&sysParam)
182	printData(sysParam, result, "Table", "First")
183	sysParam = nil
184
185	// 查询全部
186	sysParams := new([]TSysParam)
187	result = GormDB.Find(&sysParams, "enabled = ?", true)
188	// 查询可用数据
189	// result = GormDB.Find(&sysParams, "enabled = ?", true)
190	printData(&sysParams, result, "Find", "(all)")
191
192	// 按 AND 条件查询多条
193	sysParams = new([]TSysParam)
194	result = GormDB.Find(&sysParams, TSysParam{Enabled: true, CreateBy: "00000"})
195	// 不使用结构体,直接使用字段 Map
196	// result = GormDB.Find(&sysParams, map[string]interface{}{"enabled": true, "create_by": "00000"})
197	printData(&sysParams, result, "Find", "(AND)")
198
199	// 按 OR 条件查询多条
200	sysParams = new([]TSysParam)
201	result = GormDB.Where("enabled", true).Or("create_by", "00000").Find(&sysParams)
202	printData(&sysParams, result, "Find", "(OR)")
203
204	// 按 IN 条件查询多条
205	sysParams = new([]TSysParam)
206	result = GormDB.Find(&sysParams, "id IN ?", []string{"00001", "00002"})
207	printData(&sysParams, result, "Find", "(IN)")
208
209	// 按 NOT 条件查询多条
210	sysParams = new([]TSysParam)
211	result = GormDB.Not("serial_value", 0).Find(&sysParams)
212	printData(&sysParams, result, "Find", "(NOT)")
213
214	// 分页排序查询指定字段
215	sysParams = new([]TSysParam)
216	allSysParams := new([]TSysParam)
217	result = GormDB.
218		// 每页 5 条,第二页
219		Offset(5).Limit(5).
220		Order("serial_value DESC, id").
221		Select("data_table_name", "serial_value", "serial_length").
222		Find(&sysParams)
223	printData(&sysParams, result, "Find", "(select-order-paging)")
224
225	// 消除分页,获取全部
226	unpageResult := result.Offset(-1).Limit(-1).Find(&allSysParams)
227	// 总条数 pagingResult.RowsAffected
228	printData(&allSysParams, unpageResult, "Find", "(select-order-paging-all)")
229}
230
231// 修改数据,参考 https://gorm.io/zh_CN/docs/update.html
232func updateExample() {
233	sysParam := TSysParam{
234		ID:                   "test_001", // 根据主键修改指定数据
235		DataTableName:        "test_table_001",
236		DataTableDescription: "测试表-001",
237		SerialValue:          1,
238		SerialLength:         10,
239		Enabled:              true,
240		CreateTime:           nowTime(), // CreateTime 和 CreateBy 已在标签中配置为可读、可创建、不可修改
241		CreateBy:             "00001",
242		LastUpdateTime:       nowTime(),
243		LastUpdateBy:         "00000",
244	}
245	// 更新所有字段,包含零值
246	result := GormDB.Save(&sysParam).
247		// 查询修改结果重新赋值给 sysParam
248		Find(&sysParam)
249	printData(&sysParam, result, "UPDATE", "Save")
250
251	// 更新单个字段
252	result = GormDB.Model(&sysParam).
253		Where("enabled", true).
254		Update("serial_value", sysParam.SerialValue+1).
255		Find(&sysParam)
256	printData(&sysParam, result, "UPDATE", "Model", "WhereUpdate")
257
258	// 更新多个字段,使用结构体只会更新非零值字段,要更新零值字段需要使用 Select 指定要修改的字段,或者直接使用 Select("*") 更新全部字段
259	sysParam = TSysParam{
260		ID:             "test_001", // 根据主键修改指定数据
261		SerialValue:    sysParam.SerialValue + 1,
262		SerialLength:   10,
263		Enabled:        false, // false 为 GORM Model 结构体零值,不会修改此字段
264		LastUpdateTime: nowTime(),
265		LastUpdateBy:   "00000",
266	}
267	result = GormDB.Model(&sysParam).
268		Where("enabled", true).
269		Updates(&sysParam).
270		Find(&sysParam)
271	printData(&sysParam, result, "UPDATE", "Model", "Updates")
272
273	// 使用 map 可修改零值字段
274	result = GormDB.Model(&sysParam).
275		Updates(map[string]interface{}{"serial_value": sysParam.SerialValue + 1, "enabled": false}).
276		Find(&sysParam)
277	printData(&sysParam, result, "UPDATE", "Model", "UpdatesMap")
278
279	// 使用 Omit 忽略更新指定字段
280	result = GormDB.Model(&sysParam).
281		Omit("serial_value").
282		Updates(map[string]interface{}{"serial_value": sysParam.SerialValue + 1, "enabled": true}).
283		Find(&sysParam)
284	printData(&sysParam, result, "UPDATE", "Model", "UpdatesOmit")
285}
286
287// 删除数据,参考 https://gorm.io/zh_CN/docs/delete.html
288func deleteExample() {
289	// !!! 注意,删除数据时如果未指定主键或其他条件,将会触发无条件的批量删除
290	sysParam := TSysParam{
291		ID: "test_002", // 主键
292	}
293
294	// 根据主键删除指定数据
295	result := GormDB.Delete(&sysParam)
296	sysParam = TSysParam{}
297	result.Find(&sysParam)
298	printData(&sysParam, result, "Delete")
299
300	// 通过复合条件删除数据
301	result = GormDB.Where("id LIKE ? AND data_table_name LIKE ?", "test_%", "test_table_%").
302		Delete(&sysParam).
303		Find(&sysParam)
304	printData(&sysParam, result, "DeleteWhere")
305}
306
307// 获取 GORM 日志接口
308func getLogger() logger.Interface {
309	gormLogger := logger.New(
310		// io writer
311		log.New(os.Stdout, "\r\n", log.LstdFlags),
312		logger.Config{
313			// 慢 SQL 阈值
314			SlowThreshold: 3 * time.Second,
315			// 日志级别
316			LogLevel: logger.Info,
317			// 是否启用彩色打印
318			Colorful: true,
319		},
320	)
321
322	return gormLogger
323}
324
325// 打印数据
326func printData(sysParam interface{}, result *gorm.DB, morInfo ...interface{}) {
327	jsonByte, _ := json.Marshal(&sysParam)
328
329	result.Logger.Info(nil, string(jsonByte))
330	fmt.Println("条数:", result.RowsAffected,
331		"\t错误信息:[", result.Error,
332		"]\t是否为无记录错误:", errors.Is(result.Error, gorm.ErrRecordNotFound))
333
334	if len(morInfo) > 0 {
335		fmt.Println(morInfo)
336	}
337}
338
339// 打印数据库统计信息
340func printStats() {
341	dbStats := SqlDB.Stats()
342	jsonByte, _ := json.Marshal(dbStats)
343	fmt.Println(string(jsonByte))
344
345	/*fmt.Printf(`
346	空闲连接数: %d
347	使用中的连接数: %d
348	由于达到设置的空闲连接池的最大数量而关闭的连接数: %d
349	由于达到设置的连接可空闲的最长时间而关闭的连接数: %d
350	由于达到设置的可重用连接的最长时间而关闭的连接数: %d
351	数据库的最大打开连接数: %d
352	等待的连接总数: %d
353	等待新连接被阻止的总时间: %d`, dbStats.Idle, dbStats.InUse, dbStats.MaxIdleClosed, dbStats.MaxIdleTimeClosed,
354	dbStats.MaxLifetimeClosed, dbStats.MaxOpenConnections, dbStats.WaitCount, dbStats.WaitDuration)*/
355}

内容声明

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

链接: https://zixizixi.cn/go-gorm-crud-example

来源: iTanken

本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可,转载请保留此声明。

(function() { try { var days = parseInt((new Date().getTime() - new Date(document.querySelector('.article time').innerText.replace(/ /g, '').replace(/-/g, '/')).getTime()) / 864e5, 10); days > 90 && document.querySelector('section.item__content').insertAdjacentHTML('afterBegin', ['<blockquote style="border: 1px solid #6a737d;border-width: 1px 5px;text-align: center;line-height: 36px;padding: 0 10px;">\u672c\u6587\u6700\u540e\u66f4\u65b0\u4e8e <code style="color: #FF5722;vertical-align: middle;">', days, '</code> \u5929\u524d\uff0c\u5185\u5bb9\u53ef\u80fd\u5df2\u7ecf\u4e0d\u591f\u51c6\u786e\uff0c\u8bf7\u914c\u60c5\u53c2\u8003\uff01</blockquote>' ].join('')); kbnBgImgRandom(); gitalk && gitalk.render('gitalk-container'); } catch(e) {} })();


我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=wh4u6zpyhe1d

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前提条件
  • 使用说明
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档