一个关于GORM的奇怪问题

一个关于GORM的奇怪问题

需求

一般在些查询的时候都需要一个简单的Filer功能,根据传入的参数做一个系统的筛选

  • Code
//    获取文章分类列表
func GetCategoryList(condition map[string]string) *[]mysql.ArticleCategory {
    category_list := []mysql.ArticleCategory{}
    //    根据传入的参数先筛选一遍数据
    db := filterArticleCategory(condition)

    db.Table("blog_article_group").
        Select("" +
            "blog_article_group.id, " +
            "blog_article_group.name," +
            "count(blog_article.id) AS count, " +
            "blog_article_group.created_at, " +
            "blog_article_group.updated_at").
        Joins("left join blog_article on blog_article_group.id = blog_article.g_id").
        Group("blog_article_group.id").
        Find(&category_list)

    return &category_list
}
//    更具筛选的条件先设置筛选条件
func filterArticleCategory(condition map[string]string) *gorm.DB {
    if _, ok := condition["name"]; ok && condition["name"] != "" {
        db = db.Where("name like ?", "%"+condition["name"]+"%")
    }
    return db
}

查询结果

  • 第一次
curl http://127.0.0.1:9000/article_category

SELECT
    blog_article_group.id,
    blog_article_group.NAME,
    count( blog_article.id ) AS count,
    blog_article_group.created_at,
    blog_article_group.updated_at 
FROM
    `blog_article_group`
    LEFT JOIN blog_article ON blog_article_group.id = blog_article.g_id 
GROUP BY
    blog_article_group.id
  • 第二次
curl http://127.0.0.1:9000/article_category?name=la

SELECT
    blog_article_group.id,
    blog_article_group.NAME,
    count( blog_article.id ) AS count,
    blog_article_group.created_at,
    blog_article_group.updated_at 
FROM
    `blog_article_group`
    LEFT JOIN blog_article ON blog_article_group.id = blog_article.g_id 
WHERE
    ( NAME LIKE '%la%' ) 
GROUP BY
    blog_article_group.id
  • 第三次
curl http://127.0.0.1:9000/article_category?name=la

SELECT
    blog_article_group.id,
    blog_article_group.NAME,
    count( blog_article.id ) AS count,
    blog_article_group.created_at,
    blog_article_group.updated_at 
FROM
    `blog_article_group`
    LEFT JOIN blog_article ON blog_article_group.id = blog_article.g_id 
WHERE
    ( NAME LIKE '%la%' ) 
    AND ( NAME LIKE '%la%' ) 
GROUP BY
    blog_article_group.id
  • 第四次
curl http://127.0.0.1:9000/article_category?name=la

SELECT
    blog_article_group.id,
    blog_article_group.NAME,
    count( blog_article.id ) AS count,
    blog_article_group.created_at,
    blog_article_group.updated_at 
FROM
    `blog_article_group`
    LEFT JOIN blog_article ON blog_article_group.id = blog_article.g_id 
WHERE
    ( NAME LIKE '%la%' ) 
    AND ( NAME LIKE '%la%' ) 
    AND ( NAME LIKE '%la%' ) 
GROUP BY
    blog_article_group.id

问题分析

在多次查询的时候filer函数中的where语句会执行多次,最终导致出现多个AND.

  • 每个请求都是一个goruntime,其中的map也是独立的不会出现冲突
  • GORM在版本之后返回的db都是指针,已经做好了全局的连接池管理

没有看过GORM的源码,初步估计是全局返回的db指针的问题。

Gorm implements method chaining interface, so you could write code like this:

db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")

// create a new relation
tx := db.Where("name = ?", "jinzhu")

// add more filter
if someCondition {
    tx = tx.Where("age = ?", 20)
} else {
    tx = tx.Where("age = ?", 30)
}

if yetAnotherCondition {
    tx = tx.Where("active = ?", 1)
}

Query won’t be generated until a immediate method, which could be useful in some cases.

Like you could extract a wrapper to handle some common logic

问题

因为使用了全局的db指针进行查询,但是内部会共享一个Scope导致查询条件重复。官方也给出了方案,就是在操作时需要将全局的db复制一份。

func GetCategoryList(condition map[string]string) *[]ArticleCategory {
    category_list := []ArticleCategory{}
    tx := filterArticleCategory(condition)

    tx.Table("blog_article_group").
        Select("" +
            "blog_article_group.id, " +
            "blog_article_group.name," +
            "count(blog_article.id) AS count, " +
            "blog_article_group.created_at, " +
            "blog_article_group.updated_at").
        Joins("left join blog_article on blog_article_group.id = blog_article.g_id").
        Group("blog_article_group.id").
        Find(&category_list)

    return &category_list
}

func filterArticleCategory(condition map[string]string) *gorm.DB {
    tx := db

    if _, ok := condition["name"]; ok && condition["name"] != "" {
        tx = db.Where("name like ?", "%"+condition["name"]+"%")
    }
    return tx
}

  Reprint please specify: KYLE LIU 一个关于GORM的奇怪问题

 Previous
【转】深度解密Go语言之context 【转】深度解密Go语言之context
这是你自定义的文章摘要内容,如果这个属性有值,文章卡片摘要就显示这段文字,否则程序会自动截取文章的部分内容作为摘要
2019-06-12
Next 
【转】深度解密Go语言之unsafe 【转】深度解密Go语言之unsafe
这是你自定义的文章摘要内容,如果这个属性有值,文章卡片摘要就显示这段文字,否则程序会自动截取文章的部分内容作为摘要
2019-06-03
  TOC