There are three kinds of methods in GORM: , Finisher Method, New Session Method.

After a Chain method, Finisher Method, GORM returns an initialized *gorm.DB instance, which is NOT safe to reuse anymore, or new generated SQL might be polluted by the previous conditions, for example:

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

In order to reuse a initialized *gorm.DB instance, you can use a New Session Method to create a shareable *gorm.DB, e.g:

Chain methods are methods to modify or add Clauses to current Statement, like:

Here is , also check out the SQL Builder for more details about .

Finishers are immediate methods that execute registered callbacks, which will generate and execute SQL, like those methods:

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

Check out here.

After a Chain method, Finisher Method, GORM returns an initialized *gorm.DB instance, which is NOT safe to reuse anymore, you should use a New Session Method to mark the *gorm.DB as shareable.

Let’s explain it with examples:

Example 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("age = ?", 18)` is the second chain method call, it reuses the above `*gorm.Statement`, adds new condition `age = 18` to it
  5. // SELECT * FROM users WHERE name = 'jinzhu' AND age = 18;
  6. db.Where("name = ?", "jinzhu2").Where("age = ?", 20).Find(&users)
  7. // `Where("name = ?", "jinzhu2")` is also the first chain method call, it creates a new `*gorm.Statement`
  8. // `Where("age = ?", 20)` reuses the above `Statement`, and add conditions to it
  9. // `Find(&users)` is a finisher method, it executes registered Query Callbacks, generates and runs the following SQL:
  10. // SELECT * FROM users WHERE name = 'jinzhu2' AND age = 20;
  11. db.Find(&users)
  12. // `Find(&users)` is a finisher method call, it also creates a new `Statement` and executes registered Query Callbacks, generates and runs the following SQL:
  13. // SELECT * FROM users;

(Bad) Example 2:

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