子兮子兮 子兮子兮

No can, but will.

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

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

前提条件

  • 安装 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 运行代码查看效果
  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 国际许可协议进行许可,转载请保留此声明