gorm 遇坑总结

9 篇文章 0 订阅
4 篇文章 0 订阅

time 包 和 gorm 执行的问题

知识点

我们都知道,使用 golang 的 time 包可以对时间格式进行转换,比如:

  • time.xxx.Format() 可以将 time.time 格式转换为 string 格式
  • time.Parse 可以将 string 格式转换为 time.time 格式

坑点

time.Parse 默认转出来是 +0000 UTC 时间,不是中国东八区的 +0800 CST 时间,传给数据库执行的时候,会出现时间推迟 8 小时的情况,且不好排查(因为 SQL debug 打印出来的看不出异常,拿着语句直接去数据库上可以执行)。
在尝试了多种 SQL 姿势之后,还是一样的效果,最后连上 MySQL 分析实际执行的语句才发现异常。

到 MySQL 上查看执行的查询语句的方法:

pager grep [ip]     # 设置过滤出执行脚本的机器 IP
show full processlist   # 查看 MYSQL 现在正在执行的语句

解决

需要用 time.ParseInLocation 方法替换 time.Parse ,这样转换出来的时间就是 +0800 CST 时间

执行原生 SQL 问题

知识点

在执行一些复杂语句或者排查问题的时候,会直接使用 原生 SQL ,这样可能会直观一些;

坑点

原生 SQL 执行查询时,默认只能选出一行数据来,需要查询多行时,得多一步处理

https://jasperxu.github.io/gorm-zh/advanced.html#sb

解决

var userInfo []*UserInfo  
// 原生SQL  
rs := "SELECT name,age,sum(val) as num FROM `t_user_stat_20221026`  WHERE (uid = xxx and dt > '2022-10-26 00:20:00' and dt <= '2022-10-26 09:40:00' and op_code = 'xxx') GROUP BY name,age"  
rows, _ := db.Debug().Raw(rs).Rows()  
defer rows.Close()  
for rows.Next() {  
   var uu UserInfo  
   db.ScanRows(rows, &uu)  
   // 需要一行一行的 scan 解析出来,然后再 append 到最后返回的数据里
   userInfo = append(userInfo, &uu)  
}  
fmt.Println(UserInfo)  
for _, u := range UserInfo {  
   fmt.Println(*u)  
}

传入和返回值问题

注意点

传入接收结果集的变量只能为 Struct 类型或 Slice 类型;

  • 当传入变量为 Slice 类型时,任何条件下均不会抛出 ErrRecordNotFound 错误
  • 当传入变量为 Struc 类型时,如果检索出来的数据为 0 条,会抛出 ErrRecordNotFound 错误。

传入接收结果集的变量为 Slice 时的写法:

func funcName(xxx) ([]*structA,error) {
	var aa []*structA
	query := db.Table(xx).Select(xxx).Where(xxx).Find(&aa)
	if query.Error != nil{
		return nil,query.Error
	}
	if query.RecordNotFound() {
		return nil,nil
	}
	return aa, nil
}

传入接收结果集的变量为 struct 时的写法:

func funcName(xxx) (*structA,error) {
	var aa structA
	query := db.Table(xx).Select(xxx).Where(xxx).Find(&aa)
	if query.Error != nil{
		return nil,query.Error
	}
	if query.RecordNotFound() {
		return nil,nil
	}
	return &aa, nil
}

注意:传入值为 struct 的写法,容易写错,很容易报 unsupported destination, should be slice or struct 错误

https://juejin.cn/post/6844903971501375496
https://www.cnblogs.com/taoshihan/p/16044386.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
gorm scopes是Golang中使用的一种功能,用定义和应用查询作用域。它可以帮助我们在查询数据库时,根据不同的条件和需求,动态地构建查询语句。 使用gorm scopes,我们可以将一组查询条件封装成一个作用域(scope),然后在需要的时候应用到查询中。这样可以使代码更加模块化和可复用,同时也能提高查询的灵活性和可读性。 在gorm中,我们可以通过定义结构体的方法来创建作用域。这些方法需要接收一个gorm.DB类型的参数,并返回一个gorm.DB类型的结果。在方法内部,我们可以使用gorm提供的各种查询方法来构建查询条件,例如Where、Order、Limit等。 下面是一个使用gorm scopes的示例: ```go type User struct { ID uint Name string Age int } func (db *gorm.DB) AgeGreaterThan(age int) *gorm.DB { return db.Where("age > ?", age) } func main() { db, err := gorm.Open("mysql", "user:password@tcp(localhost:3306)/database") if err != nil { panic(err) } defer db.Close() var users []User db.Scopes(db.AgeGreaterThan(18)).Find(&users) } ``` 在上面的示例中,我们定义了一个名为AgeGreaterThan的作用域,它接收一个年龄参数,并返回一个添加了查询条件的gorm.DB对象。然后,在main函数中,我们通过调用Scopes方法并传入AgeGreaterThan作用域,来应用该作用域到查询中。 这样,最终执行的查询语句将会是`SELECT * FROM users WHERE age > 18`,并将结果存储到users变量中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值