gorm踩坑笔记1

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

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

查看所有标签

猜你喜欢:

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

About Face 2.0

About Face 2.0

Alan Cooper、Robert M. Reimann / Wiley / March 17, 2003 / USD 35.00

First published seven years ago-just before the World Wide Web exploded into dominance in the software world-About Face rapidly became a bestseller. While the ideas and principles in the original book......一起来看看 《About Face 2.0》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具