gorm踩坑笔记1

栏目: IT技术 · 发布时间: 5年前

内容简介:最近在用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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Objective-C编程

Objective-C编程

[美] Aaron Hillegass / 夏伟频、李骏 / 华中科技大学出版社 / 2012-9-25 / 58.00元

《Objective-C编程》讲述Objective-C编程语言和基本的iOS/Mac开发知识。作者首先从基本的编程概念讲起(变量、条件语句、循环结构等),接着用浅显易懂的语言讲解Objective-C和Foundation的知识,包括Objective-C的基本语法、 Foundation常用类 、内存管理、常用设计模式等,最后手把手教读者编写完整的、基于事件驱动的iOS/Mac应用。作者还穿插......一起来看看 《Objective-C编程》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试