GORM 允许进行链式操作,所以您可以像这样写代码:

  1. db.Where("name = ?", "jinzhu").Where("age = ?", 18).First(&user)

GORM 中有三种类型的方法: 链式方法终结方法新建会话方法

链式方法, 终结方法之后, GORM 返回一个初始化的 *gorm.DB 实例,实例不能安全地重复使用,并且新生成的 SQL 可能会被先前的条件污染,例如:

  1. queryDB := DB.Where("name = ?", "jinzhu")
  2. queryDB.Where("age > ?", 10).First(&user)
  3. // SELECT * FROM users WHERE name = "jinzhu" AND age > 10
  4. queryDB.Where("age > ?", 20).First(&user2)
  5. // SELECT * FROM users WHERE name = "jinzhu" AND age > 10 AND age > 20

为了重新使用初始化的 *gorm.DB 实例, 您可以使用 新建会话方法 创建一个可共享的 *gorm.DB, 例如:

  1. queryDB := DB.Where("name = ?", "jinzhu").Session(&gorm.Session{})
  2. queryDB.Where("age > ?", 10).First(&user)
  3. // SELECT * FROM users WHERE name = "jinzhu" AND age > 10
  4. queryDB.Where("age > ?", 20).First(&user2)
  5. // SELECT * FROM users WHERE name = "jinzhu" AND age > 20

链式方法

链式方法是将 Clauses 修改或添加到当前 Statement 的方法,例如:

Where, Select, Omit, Joins, Scopes, Preload, Raw (Raw can’t be used with other chainable methods to build SQL)…

这是 完整方法列表,也可以查看 SQL 构建器 获取更多关于 Clauses 的信息

终结方法

终结(方法) 是会立即执行注册回调的方法,然后生成并执行 SQL,比如这些方法:

Create, First, Find, Take, Save, Update, Delete, Scan, Row, Rows

查看完整方法列表

新建会话方法

GORM 定义了 SessionWithContextDebug 方法做为 新建会话方法,查看会话 获取详情.

链式方法, Finisher 方法之后, GORM 返回一个初始化的 *gorm.DB 实例,不能安全地再使用。您应该使用 新建会话方法 来标记 *gorm.DB 为可共享。

让我们用实例来解释它:

示例 1:

  1. db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
  2. // db is a new initialized `*gorm.DB`, which is safe to reuse
  3. db.Where("name = ?", "jinzhu").Where("age = ?", 18).Find(&users)
  4. // `Where("name = ?", "jinzhu")` is the first chain method call, it will create an initialized `*gorm.DB` instance, aka `*gorm.Statement`
  5. // `Where("age = ?", 18)` is the second chain method call, it reuses the above `*gorm.Statement`, adds new condition `age = 18` to it
  6. // `Find(&users)` is a finisher method, it executes registered Query Callbacks, which generates and runs the following SQL:
  7. // SELECT * FROM users WHERE name = 'jinzhu' AND age = 18;
  8. db.Where("name = ?", "jinzhu2").Where("age = ?", 20).Find(&users)
  9. // `Where("name = ?", "jinzhu2")` is also the first chain method call, it creates a new `*gorm.Statement`
  10. // `Where("age = ?", 20)` reuses the above `Statement`, and add conditions to it
  11. // `Find(&users)` is a finisher method, it executes registered Query Callbacks, generates and runs the following SQL:
  12. // SELECT * FROM users WHERE name = 'jinzhu2' AND age = 20;
  13. db.Find(&users)
  14. // `Find(&users)` is a finisher method call, it also creates a new `Statement` and executes registered Query Callbacks, generates and runs the following SQL:
  15. // SELECT * FROM users;

(错误的) 示例2:

  1. db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
  2. // db is a new initialized *gorm.DB, which is safe to reuse
  3. tx := db.Where("name = ?", "jinzhu")
  4. // `Where("name = ?", "jinzhu")` returns an initialized `*gorm.Statement` instance after chain method `Where`, which is NOT safe to reuse
  5. // good case
  6. tx.Where("age = ?", 18).Find(&users)
  7. // `tx.Where("age = ?", 18)` use the above `*gorm.Statement`, adds new condition to it
  8. // `Find(&users)` is a finisher method call, it executes registered Query Callbacks, generates and runs the following SQL:
  9. // SELECT * FROM users WHERE name = 'jinzhu' AND age = 18
  10. // bad case
  11. tx.Where("age = ?", 28).Find(&users)
  12. // `tx.Where("age = ?", 28)` also use the above `*gorm.Statement`, and keep adding conditions to it
  13. // So the following generated SQL is polluted by the previous conditions:
  14. // SELECT * FROM users WHERE name = 'jinzhu' AND age = 18 AND age = 28;

示例 3:

  1. db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
  2. // db is a new initialized *gorm.DB, which is safe to reuse
  3. tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{})
  4. tx := db.Where("name = ?", "jinzhu").WithContext(context.Background())
  5. tx := db.Where("name = ?", "jinzhu").Debug()
  6. // `Session`, `WithContext`, `Debug` returns `*gorm.DB` marked as safe to reuse, newly initialized `*gorm.Statement` based on it keeps current conditions
  7. // good case
  8. tx.Where("age = ?", 18).Find(&users)
  9. // SELECT * FROM users WHERE name = 'jinzhu' AND age = 18
  10. // good case
  11. tx.Where("age = ?", 28).Find(&users)
  12. // SELECT * FROM users WHERE name = 'jinzhu' AND age = 28;