内容简介:最近在用gorm查询满足某个条件的所有记录中最新的记录,代码可参考下面的例子,具体查询语句如下所示,目的是查询满足条件host_id=1的所有记录中按时间倒序,然后返回最新的记录。完整的case执行结果,从执行结果中发现,返回了第一条记录,显然不是想要的结果,预期返回的应该是第二条记录,而实际返回的是第一条记录。
最近在用gorm查询满足某个条件的所有记录中最新的记录,代码可参考下面的例子,具体查询语句如下所示,目的是查询满足条件host_id=1的所有记录中按时间倒序,然后返回最新的记录。
orm.First(&hostStat, "host_id = ?", 1).Order("time desc").Error 复制代码
完整的case
package main import ( "os" log "github.com/Sirupsen/logrus" "github.com/jinzhu/gorm" _ "github.com/mattn/go-sqlite3" "time" ) type HostStat struct { Id int HostId int Message string Time time.Time } func main() { if _,err:=os.Stat("test.db");err==nil{ os.Remove("test.db") } orm, err := gorm.Open("sqlite3", "test.db") if err != nil { log.Errorf("gorm open err:%s", err) return } orm.AutoMigrate(&HostStat{}) orm.Save(&HostStat{ HostId: 1, Message: "first", Time: time.Now(), }) time.Sleep(1 * time.Second) orm.Save(&HostStat{ HostId: 1, Message: "second", Time: time.Now(), }) var hostStatList []HostStat if err := orm.Find(&hostStatList).Error; err != nil { log.Errorf("gorm find host stat list error:%s", err) return } for _,host:=range hostStatList{ log.Println(host) } var hostStat HostStat if err := orm.First(&hostStat, "host_id = ?", 1).Order("time desc").Error; err != nil { log.Errorf("gorm get hostStat err:%s", err) return } log.Println(hostStat.Message) } 复制代码
执行结果,从执行结果中发现,返回了第一条记录,显然不是想要的结果,预期返回的应该是第二条记录,而实际返回的是第一条记录。
INFO[0001] {1 1 first 2020-02-25 11:55:35.855536 +0800 +0800} INFO[0001] {2 1 second 2020-02-25 11:55:36.860022 +0800 +0800} INFO[0001] first 复制代码
解决过程
排查过程
首先需要分析一下,为什么先first,在order会导致直接返回第一条记录,在下面的代码中,我打开的gorm的debug,并将order和first的顺序换了一下,做对比。
if err := orm.Debug().First(&hostStat, "host_id = ?", 1).Order("time desc").Error; err != nil { log.Errorf("gorm get hostStat err:%s", err) return } log.Println(hostStat.Message) if err := orm.Debug().Order("time desc").Find(&hostStat, "host_id = ?", 1).Limit(1).Error; err != nil { log.Errorf("gorm get hostStat err:%s", err) return } log.Println(hostStat.Message) 复制代码
输出结果显示两种做法都返回了第一条记录,从debug信息里看到
- 对于First().Order("time desc")的语法,gorm直接忽略了Order的语法
- 对于Order("time desc").First()的语法,gorm添加了WHERE ("id" = '1')的限制,这个操作令我震惊,直接加了id=1的条件限制,这样的话,就不会查找到id=2的记录。
$ go run main.go INFO[0001] {1 1 first 2020-02-25 15:38:30.467259 +0800 +0800} INFO[0001] {2 1 second 2020-02-25 15:38:31.470624 +0800 +0800} (/Users/zhangyi/go/src/goscripts/gorm/main.go:52) [2020-02-25 15:38:31] [0.34ms] SELECT * FROM "host_stats" WHERE (host_id = '1') ORDER BY "host_stats"."id" ASC LIMIT 1 INFO[0001] first (/Users/zhangyi/go/src/goscripts/gorm/main.go:58) [2020-02-25 15:38:31] [0.26ms] SELECT * FROM "host_stats" WHERE ("id" = '1') AND ((host_id = '1')) ORDER BY time desc INFO[0001] first 复制代码
解决方案
对于这种问题最好的解决方案就是手动拼写sql,使用gorm.Raw(),下面给出了两种对比的做法。
if err := orm.Debug().First(&hostStat, "host_id = ?", 1).Order("time desc").Error; err != nil { log.Errorf("gorm get hostStat err:%s", err) return } log.Println(hostStat.Message) if err := orm.Debug().Raw("select * from host_stats where host_id = ? order by time desc limit 1", 1).Scan(&hostStat).Error; err != nil { log.Errorf("gorm get hostStat err:%s", err) return } log.Println(hostStat.Message) 复制代码
输出结果如下所示,从结果中可以看出使用Raw方法的 sql 语句和结果符合预期。
$ go run main.go INFO[0001] {1 1 first 2020-02-25 15:48:17.075904 +0800 +0800} INFO[0001] {2 1 second 2020-02-25 15:48:18.076935 +0800 +0800} (/Users/zhangyi/go/src/goscripts/gorm/main.go:52) [2020-02-25 15:48:18] [0.33ms] SELECT * FROM "host_stats" WHERE (host_id = '1') ORDER BY "host_stats"."id" ASC LIMIT 1 INFO[0001] first (/Users/zhangyi/go/src/goscripts/gorm/main.go:58) [2020-02-25 15:48:18] [0.27ms] select * from host_stats where host_id = '1' order by time desc limit 1 INFO[0001] second 复制代码
以上所述就是小编给大家介绍的《gorm踩坑笔记1》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 【每日笔记】【Go学习笔记】2019-01-04 Codis笔记
- 【每日笔记】【Go学习笔记】2019-01-02 Codis笔记
- 【每日笔记】【Go学习笔记】2019-01-07 Codis笔记
- vue笔记3,计算笔记
- Mysql Java 驱动代码阅读笔记及 JDBC 规范笔记
- 【每日笔记】【Go学习笔记】2019-01-16 go网络编程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C++标准模板库编程实战
Ivor Horton / 郭小虎、程聪 / 2017-1
《C++标准模板库编程实战》介绍最新的C++14标准的API、库和扩展,以及如何将它们运用到C++14程序中。在书中,作者Ivor Horton 则阐述了什么是STL,以及如何将它们应用到程序中。我们将学习如何使用容器、迭代器,以及如何定义、创建和应用算法。此外,还将学习函数对象和适配器,以及它们的用法。 阅读完本书之后,你将能够了解如何扩展STL,如何定义自定义类型的C++组件,你还将能够......一起来看看 《C++标准模板库编程实战》 这本书的介绍吧!