欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GO中GORM 使用教程

 更新時間:2025年02月20日 09:33:30   作者:小青柑-  
GORM是Go語言的ORM庫,它將關(guān)系型數(shù)據(jù)庫表與Go語言結(jié)構(gòu)體映射,提供便捷的數(shù)據(jù)庫操作,本文就來介紹有下GO中GORM 使用教程,具有一定的參考價值,感興趣的可以了解一下

GORM 是一個用于 Go 語言的 ORM(Object-Relational Mapping) 庫。它將關(guān)系型數(shù)據(jù)庫的表與 Go 語言中的結(jié)構(gòu)體相映射,允許開發(fā)者以面向?qū)ο蟮姆绞讲僮鲾?shù)據(jù)庫,而不需要直接編寫 SQL 語句。通過 GORM,開發(fā)者可以利用 Go 語言的結(jié)構(gòu)體和方法來執(zhí)行常見的數(shù)據(jù)庫操作(如查詢、插入、更新、刪除等),大大簡化了與數(shù)據(jù)庫的交互過程。

1. 安裝 GORM

首先,你需要安裝 GORM 庫。打開終端并運行以下命令:

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite  # 示例數(shù)據(jù)庫,可以根據(jù)需求更換為其他數(shù)據(jù)庫驅(qū)動

2. 創(chuàng)建基礎(chǔ)結(jié)構(gòu)體

ORM的一個核心概念是結(jié)構(gòu)體,它代表數(shù)據(jù)庫表的一個映射。例如,假設(shè)你有一個“用戶”表,我們可以創(chuàng)建一個 User 結(jié)構(gòu)體來表示它。

package main

import (
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type User struct {
    ID        uint   `gorm:"primaryKey"`  // 主鍵
    Name      string `gorm:"size:100"`    // 用戶名字段,限制長度為100
    Age       uint   // 用戶年齡
    CreatedAt time.Time  // 創(chuàng)建時間(GORM 會自動管理)
}

func main() {
    // 創(chuàng)建數(shù)據(jù)庫連接
    db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect to the database")
    }

    // 自動遷移:通過GORM根據(jù)結(jié)構(gòu)體自動創(chuàng)建表
    db.AutoMigrate(&User{})
}

在 GORM 中,結(jié)構(gòu)體字段的標(biāo)簽(tags)用于定義和控制如何將 Go 結(jié)構(gòu)體映射到數(shù)據(jù)庫表的列。GORM 支持很多標(biāo)簽,可以配置數(shù)據(jù)庫表的列屬性、索引、關(guān)系等。以下是常見的 GORM 字段標(biāo)簽和它們的作用:

標(biāo)簽描述示例
primaryKey指定字段為主鍵。gorm:"primaryKey"
size指定字段的大小,通常用于字符串字段。gorm:"size:100"
unique創(chuàng)建唯一索引,確保字段值唯一。gorm:"unique"
not null指定字段不能為空。gorm:"not null"
default指定字段的默認值。gorm:"default:0"
autoIncrement設(shè)置字段為自增字段。通常用于整數(shù)類型的主鍵。gorm:"autoIncrement"
index為字段創(chuàng)建索引。gorm:"index"
uniqueIndex為字段創(chuàng)建唯一索引。gorm:"uniqueIndex"
index:<name>創(chuàng)建帶有自定義名稱的索引。gorm:"index:idx_name"
foreignKey指定外鍵字段,在一對多或多對多關(guān)系中使用。gorm:"foreignKey:UserID"
references指定外鍵關(guān)系中引用的字段。gorm:"references:ID"
embedded嵌入一個結(jié)構(gòu)體,扁平化嵌入的結(jié)構(gòu)體字段到父結(jié)構(gòu)體中。gorm:"embedded"
preload在查詢時預(yù)加載關(guān)聯(lián)數(shù)據(jù)。gorm:"preload"
createdAt自動生成的創(chuàng)建時間戳字段。gorm:"autoCreateTime"
updatedAt自動生成的更新時間戳字段。gorm:"autoUpdateTime"
deletedAt自動生成的刪除時間戳字段,支持軟刪除。gorm:"softDelete"
softDelete用于支持軟刪除功能。通常與 DeletedAt 配合使用。gorm:"index"
column指定數(shù)據(jù)庫中的列名,當(dāng)字段名與列名不一致時使用。gorm:"column:db_column_name"
type指定字段在數(shù)據(jù)庫中的類型,通常用于特殊類型(如 JSON)。gorm:"type:text"
many2many用于多對多關(guān)系,指定連接表的名稱。gorm:"many2many:user_posts"

這個表格展示了 GORM 中常用的字段標(biāo)簽以及它們?nèi)绾斡绊憯?shù)據(jù)庫表結(jié)構(gòu),幫助開發(fā)者更好地理解和使用 GORM 進行數(shù)據(jù)庫操作。

3. 數(shù)據(jù)庫連接與配置

在上面的示例中,我們使用了 gorm.Open() 來連接 SQLite 數(shù)據(jù)庫。如果你使用 MySQL 或 Postgres 等其他數(shù)據(jù)庫,可以更換相應(yīng)的驅(qū)動。

例如,連接到 MySQL 數(shù)據(jù)庫的代碼如下:

db, err := gorm.Open(mysql.Open("user:password@tcp(localhost:3306)/dbname"), &gorm.Config{})

4. 數(shù)據(jù)庫操作

4.1 創(chuàng)建記錄

你可以使用 Create 方法來插入數(shù)據(jù)。下面是如何插入一個新用戶:

func createUser(db *gorm.DB) {
    user := User{Name: "John Doe", Age: 30}
    result := db.Create(&user)
    if result.Error != nil {
        panic("Failed to create user")
    }
    fmt.Println("User created:", user.ID)
}

代碼中db.Create(&user) 使用 & 符號是因為我們要傳遞結(jié)構(gòu)體 user 的 指針 給 Create 方法。具體來說,這樣做有以下幾個原因:

  • 指針傳遞可以修改原結(jié)構(gòu)體

    GORM 的 Create 方法接受結(jié)構(gòu)體的 指針,這樣它可以直接修改原始結(jié)構(gòu)體的值,而不僅僅是副本。通過傳遞指針,GORM 能夠在插入數(shù)據(jù)庫的過程中修改結(jié)構(gòu)體(例如,給結(jié)構(gòu)體的字段賦值,例如數(shù)據(jù)庫自動生成的 ID 或 CreatedAt 字段),確保結(jié)構(gòu)體反映數(shù)據(jù)庫中的最新數(shù)據(jù)。

    例如,user 的 ID 字段會在插入數(shù)據(jù)庫時由 GORM 自動賦值(通常是自增的主鍵),如果你傳遞的是結(jié)構(gòu)體的指針,Create 方法可以直接更新 user 結(jié)構(gòu)體中的 ID 字段。

  • 避免復(fù)制大結(jié)構(gòu)體

    如果你傳遞的是結(jié)構(gòu)體的副本,GORM 會先創(chuàng)建一個結(jié)構(gòu)體的拷貝并將其插入數(shù)據(jù)庫。這對于較大的結(jié)構(gòu)體來說可能會浪費內(nèi)存并降低性能。而傳遞指針避免了復(fù)制整個結(jié)構(gòu)體,只是傳遞了結(jié)構(gòu)體的內(nèi)存地址,性能更高。

  • GORM 的工作方式

    GORM 內(nèi)部使用了指針來標(biāo)識結(jié)構(gòu)體字段的變化。通過傳遞指針,GORM 可以確定結(jié)構(gòu)體的變化并進行相應(yīng)的處理。例如,在執(zhí)行 Create 時,GORM 會檢查結(jié)構(gòu)體的指針,判斷該字段是否已經(jīng)賦值、是否需要自動填充等。

4.2 查詢記錄

GORM 提供了多種查詢方式,可以通過結(jié)構(gòu)體查詢、條件查詢等方式來獲取數(shù)據(jù)。

獲取單條記錄

func getUser(db *gorm.DB) {
    var user User
    result := db.First(&user, 1)  // 查找 user 表中主鍵為 1 的記錄,并將其填充到 user 結(jié)構(gòu)體中
    if result.Error != nil {
        panic("User not found")
    }
    fmt.Println("User:", user)
}

db.First 是 GORM 提供的一個查詢方法,用于從數(shù)據(jù)庫中獲取 第一條 滿足條件的記錄。它通常用于根據(jù)主鍵或其他條件查詢數(shù)據(jù)。

db.First 的基本語法:

db.First(&model, conditions...)
  • &model 是一個指針參數(shù),表示查詢的結(jié)果將會填充到這個結(jié)構(gòu)體中。
  • conditions... 是查詢的條件,可以是主鍵或其他字段。

如果查詢成功,db.First 會把查詢到的記錄填充到 model 指針?biāo)赶虻慕Y(jié)構(gòu)體里。如果沒有找到記錄,它會返回一個錯誤。

在 db.First(&user, 1) 中,&user 是指向 user 結(jié)構(gòu)體的指針。這里傳遞指針是因為 GORM 要修改 user 結(jié)構(gòu)體的值(即填充查詢結(jié)果)。

  • 通過傳遞結(jié)構(gòu)體的指針,GORM 可以將查詢結(jié)果直接賦值到 user 結(jié)構(gòu)體中。
  • 如果你傳遞的是結(jié)構(gòu)體本身,而不是指針,查詢結(jié)果將不會填充到結(jié)構(gòu)體中,因為結(jié)構(gòu)體會作為副本傳遞到 db.First 方法,而 GORM 需要能夠修改原始結(jié)構(gòu)體的字段值。

獲取多個記錄

func getUsers(db *gorm.DB) {
    var users []User
    result := db.Find(&users)
    if result.Error != nil {
        panic("No users found")
    }
    fmt.Println("Users:", users)
}

db.Find 是 GORM 提供的查詢方法之一,用于查找多個記錄并將其存儲到傳入的切片結(jié)構(gòu)體中。

  • Find 方法會根據(jù)傳入的條件來查找記錄,可以是簡單的查詢(如所有記錄),也可以是有條件的查詢(如按字段值過濾)。
  • 傳遞給 Find 的參數(shù)是一個指針,它會將查詢到的記錄填充到指向的切片中。

db.Find(&users) 會從數(shù)據(jù)庫中查找所有記錄(或者根據(jù)傳入的查詢條件查找記錄)并將它們填充到 users 切片中。查詢的結(jié)果會是一個結(jié)構(gòu)體的集合。Find 方法默認返回所有滿足條件的記錄。

  • 如果查詢沒有條件,Find 將返回數(shù)據(jù)庫表中的所有記錄。
  • 如果你傳遞了查詢條件,Find 將根據(jù)條件過濾結(jié)果。

Find 方法的其他功能

  • 查詢條件:你可以通過傳遞查詢條件來限制查詢的結(jié)果。例如,如果你想查找年齡大于 30 的所有用戶,可以這么寫:
db.Find(&users, "age > ?", 30)

這個查詢會返回所有年齡大于 30 的用戶。

  • 分頁:Find 還支持分頁查詢。你可以通過 Limit 和 Offset 方法來實現(xiàn)分頁查詢。例如,查詢前 10 條記錄:
db.Limit(10).Find(&users)
  • 排序:你也可以通過 Order 方法來指定查詢結(jié)果的排序方式。例如,按年齡排序:
db.Order("age desc").Find(&users)
  • 返回記錄數(shù):Find 方法還會返回查詢的結(jié)果,包括查詢到的記錄數(shù)。如果沒有記錄,它會返回一個空的切片。

4.3 更新記錄

在 GORM 中,更新記錄是一個常見的操作。你可以通過 GORM 提供的幾種方法來更新記錄。以下將詳細介紹 GORM 中更新記錄的方式,包含基本更新、部分更新、批量更新等操作,并解釋每種方法的具體用法和注意事項。

基本更新:db.Save 方法

db.Save 方法用于保存(或更新)結(jié)構(gòu)體中的數(shù)據(jù)。如果結(jié)構(gòu)體的主鍵已經(jīng)存在,GORM 會執(zhí)行 更新操作;如果主鍵不存在,GORM 會執(zhí)行 插入操作(也稱為 “upsert”)。因此,db.Save 不僅適用于更新已有記錄,也適用于插入新記錄。

示例

func main() {
    var user User
    db.First(&amp;user, 1) // 查找主鍵為 1 的用戶

    user.Name = "Alice Updated" // 修改字段
    user.Age = 30

    db.Save(&amp;user) // 更新記錄
}
  • db.Save(&user) 會檢查 user 是否已有主鍵值(假設(shè)主鍵存在)。如果存在,它將執(zhí)行更新操作,將 user 結(jié)構(gòu)體中修改的字段更新到數(shù)據(jù)庫中。
  • 如果主鍵不存在,它會將 user 插入到數(shù)據(jù)庫中。

注意:

  • Save 會更新所有非零字段(即結(jié)構(gòu)體中的字段如果是空值,可能不會被更新),并且會更新所有字段,即使你沒有顯式修改某個字段。
  • 如果你希望只更新某些字段,應(yīng)該使用 Updates 或 Update 方法。

更新部分字段:db.Updates 方法

db.Updates 方法允許你更新結(jié)構(gòu)體中的 部分字段,而不是全部字段。它是一個更精確的更新方法,通常用于僅更新結(jié)構(gòu)體中某些修改了的字段。

示例

func main() {
    var user User
    db.First(&amp;user, 1) // 查找主鍵為 1 的用戶

    db.Model(&amp;user).Updates(User{Name: "Bob Updated", Age: 35})
}

在這個例子中:

  • db.Model(&user).Updates(User{Name: "Bob Updated", Age: 35}) 只會更新 user 結(jié)構(gòu)體中的 Name 和 Age 字段。
  • db.Model(&user) 表明更新的是 user 結(jié)構(gòu)體對應(yīng)的數(shù)據(jù)庫記錄。
  • Updates 方法中的參數(shù)可以是一個結(jié)構(gòu)體(如 User{Name: "Bob Updated"}),也可以是一個 map[string]interface{}(鍵是字段名,值是要更新的值)。

注意:

  • Updates 會忽略零值字段(如空字符串、零整數(shù)等),如果某個字段的值為零,它不會被更新。
  • db.Model(&user) 用于指定要更新的模型或表。
  • Updates 會將修改過的字段進行更新,但不會更新模型中未指定的字段。

單個字段更新:db.Update 方法

如果你只需要更新某個單獨的字段,可以使用 db.Update 方法。該方法用于 更新單個字段,是 db.Updates 的簡化版本,適合只更新單一字段的場景。

示例

func main() {
    var user User
    db.First(&user, 1) // 查找主鍵為 1 的用戶

    db.Model(&user).Update("Age", 40) // 只更新 Age 字段
}
  • db.Model(&user).Update("Age", 40) 會將 Age 字段更新為 40,其他字段保持不變。
  • Update 方法適用于你只需要更新單個字段的情況。

注意:

  • Update 方法只更新指定的字段,不會影響其他字段。
  • 如果字段的值為零值,Update 也會更新該字段(沒有 零值忽略 的機制)。

批量更新:db.UpdateColumn 和 db.UpdateColumns

GORM 還提供了 UpdateColumn 和 UpdateColumns 方法,主要用于 批量更新 字段。這些方法與 Update 方法類似,但它們不會觸發(fā) GORM 的鉤子(如 BeforeSave、AfterSave 等)。

UpdateColumn 示例

db.Model(&user).UpdateColumn("Age", 45)

UpdateColumn 不會觸發(fā) GORM 的 BeforeSave 和 AfterSave 鉤子,因此適用于需要繞過這些鉤子的情況。

UpdateColumns 示例

db.Model(&user).UpdateColumns(map[string]interface{}{"Age": 50, "Name": "Charlie Updated"})

UpdateColumns 會根據(jù)傳入的字段進行批量更新。與 Update 不同,它不會觸發(fā)模型的鉤子。

注意:

  • 這兩個方法直接更新字段,不會對字段的零值進行忽略。
  • 它們只進行 單字段的原子更新,不會涉及到多表關(guān)聯(lián)等操作。

條件更新:db.Where 和 db.Updates

你可以在更新時通過 Where 方法指定更新的條件。Where 方法可以與 Updates 或 Update 一起使用,以便進行條件更新。

示例

db.Model(&User{}).Where("age > ?", 30).Updates(User{Name: "Updated Name"})
  • 這個示例中,Where("age > ?", 30) 限定了更新條件,只有年齡大于 30 的用戶才會被更新。
  • Updates(User{Name: "Updated Name"}) 更新所有符合條件的用戶的 Name 字段。

注意:

  • Where 可以幫助你構(gòu)造復(fù)雜的更新條件,但也可以根據(jù)需要單獨使用(例如,按 ID 更新某些記錄)。

批量更新(多個記錄)

你可以使用 db.Model() 方法和 db.Updates() 方法來批量更新多個記錄。下面是一個批量更新的示例:

示例

db.Model(&User{}).Where("age > ?", 30).Updates(User{Name: "Batch Update"})
  • 這個例子會更新所有 age > 30 的用戶,將它們的 Name 字段修改為 "Batch Update"。

注意:

  • Updates 會更新所有符合條件的記錄,而不是只更新一個記錄。

使用事務(wù)更新多個記錄

如果你需要確保多個更新操作的原子性,可以將更新操作放入一個事務(wù)中。在 GORM 中,事務(wù)通過 db.Begin() 開始,db.Commit() 提交,db.Rollback() 回滾。

示例

tx := db.Begin()

// 執(zhí)行多個更新操作
tx.Model(&User{}).Where("age > ?", 30).Updates(User{Name: "Transactional Update"})
tx.Model(&User{}).Where("name = ?", "Bob").Update("Age", 40)

if err := tx.Commit().Error; err != nil {
    tx.Rollback()
    fmt.Println("Error:", err)
    return
}
  • db.Begin() 開始一個事務(wù)。
  • tx.Commit() 提交事務(wù),tx.Rollback() 在出錯時回滾事務(wù),確保所有操作的原子性。

4.4 刪除記錄

刪除記錄可以使用 Delete 方法:

func deleteUser(db *gorm.DB) {
    var user User
    db.First(&user, 1)  // 查找要刪除的用戶

    // 刪除用戶
    result := db.Delete(&user)
    if result.Error != nil {
        panic("Failed to delete user")
    }
    fmt.Println("User deleted:", user.ID)
}

5. 關(guān)系與關(guān)聯(lián)查詢

GORM 支持表之間的關(guān)系映射。比如,我們有 User 和 Post 之間的關(guān)系。一個用戶可以有多個帖子,可以使用 has many 關(guān)系。

5.1 定義關(guān)聯(lián)結(jié)構(gòu)體

type Post struct {
    ID     uint
    Title  string
    Body   string
    UserID uint  // 外鍵
    User   User  // 關(guān)聯(lián)的 User
}

5.2 關(guān)聯(lián)查詢

假設(shè)我們有 User 和 Post 兩個表,你可以使用 Preload 來加載關(guān)聯(lián)的 Post 數(shù)據(jù)。

func getUserWithPosts(db *gorm.DB) {
    var user User
    db.Preload("Posts").First(&user, 1)
    fmt.Println("User:", user.Name)
    fmt.Println("Posts:", user.Posts)
}

5.3 創(chuàng)建關(guān)聯(lián)記錄

當(dāng)你插入一個帶有關(guān)聯(lián)的記錄時,可以使用 Create 方法來同時插入主表和從表數(shù)據(jù):

func createUserWithPosts(db *gorm.DB) {
    user := User{Name: "Alice", Age: 28, Posts: []Post{
        {Title: "Post 1", Body: "This is the first post"},
        {Title: "Post 2", Body: "This is the second post"},
    }}
    db.Create(&user)
    fmt.Println("User and Posts created:", user)
}

6. 事務(wù)

在 GORM 中,事務(wù)(Transaction) 是一個非常重要的概念,尤其是在需要確保多個數(shù)據(jù)庫操作要么全部成功,要么全部失敗的情況下。事務(wù)能夠保證操作的原子性、一致性、隔離性和持久性(即 ACID 特性)。如果在事務(wù)中的某個操作失敗,事務(wù)可以回滾,使得數(shù)據(jù)庫回到事務(wù)開始之前的狀態(tài)。

事務(wù)(Transaction)是一組數(shù)據(jù)庫操作,它們要么全部執(zhí)行,要么在發(fā)生錯誤時全部不執(zhí)行。事務(wù)在數(shù)據(jù)庫操作中提供了 原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation) 和 持久性(Durability)(合稱為ACID特性):

  • 原子性(Atomicity):事務(wù)中的所有操作要么都執(zhí)行,要么都不執(zhí)行。即事務(wù)是不可分割的整體。
  • 一致性(Consistency):事務(wù)執(zhí)行前后,數(shù)據(jù)庫的狀態(tài)必須是一致的,符合數(shù)據(jù)庫的完整性約束。
  • 隔離性(Isolation):一個事務(wù)的執(zhí)行不會被其他事務(wù)干擾。事務(wù)的執(zhí)行是相互隔離的。
  • 持久性(Durability):一旦事務(wù)提交,其對數(shù)據(jù)庫的更改是永久性的,不會丟失。

在 GORM 中,你可以通過 db.Begin() 來啟動一個事務(wù),使用 tx.Commit() 來提交事務(wù),使用 tx.Rollback() 來回滾事務(wù)。以下是 GORM 中事務(wù)的常見用法。

6.1. 開始事務(wù):db.Begin()

你可以通過 db.Begin() 啟動一個事務(wù)。這個方法會返回一個事務(wù)對象(*gorm.DB 類型),通過這個對象你可以執(zhí)行數(shù)據(jù)庫操作。

tx := db.Begin()  // 開始事務(wù)
  • db.Begin() 會創(chuàng)建一個事務(wù)。
  • 返回的 tx 是事務(wù)對象,所有的數(shù)據(jù)庫操作都應(yīng)通過 tx 來執(zhí)行,而不是直接使用 db。

6.2 執(zhí)行事務(wù)中的操作

在事務(wù)中,你可以進行一系列的數(shù)據(jù)庫操作。所有的操作都應(yīng)該通過事務(wù)對象 tx 來執(zhí)行,而不是直接通過 db 執(zhí)行。

示例

tx := db.Begin()  // 開始事務(wù)

// 執(zhí)行多個數(shù)據(jù)庫操作
if err := tx.Create(&user).Error; err != nil {
    tx.Rollback()  // 操作失敗,回滾事務(wù)
    return err
}

if err := tx.Model(&user).Update("Age", 30).Error; err != nil {
    tx.Rollback()  // 操作失敗,回滾事務(wù)
    return err
}
  • tx.Create(&user) 會在事務(wù)中插入一條記錄。
  • tx.Model(&user).Update("Age", 30) 會在事務(wù)中更新該記錄。

6.3 提交事務(wù):tx.Commit()

當(dāng)所有的操作都執(zhí)行成功時,可以調(diào)用 tx.Commit() 提交事務(wù),將所有的變更永久保存到數(shù)據(jù)庫。

if err := tx.Commit().Error; err != nil {
    tx.Rollback()  // 提交失敗,回滾事務(wù)
    return err
}
  • tx.Commit() 會提交事務(wù),執(zhí)行所有的操作并將它們持久化到數(shù)據(jù)庫。

6.4 回滾事務(wù):tx.Rollback()

如果在事務(wù)過程中遇到錯誤,應(yīng)該調(diào)用 tx.Rollback() 來回滾事務(wù)。這樣,所有在事務(wù)中執(zhí)行的操作都會撤銷,數(shù)據(jù)庫將恢復(fù)到事務(wù)開始前的狀態(tài)。

if err := tx.Rollback().Error; err != nil {
    fmt.Println("Error during rollback:", err)
    return err
}
  • tx.Rollback() 會撤銷事務(wù)中的所有操作。

6.5 在事務(wù)中使用錯誤處理

通常,事務(wù)中的操作需要進行錯誤處理。只要有任何一項操作失敗,應(yīng)該調(diào)用 tx.Rollback() 進行回滾。

tx := db.Begin()

// 執(zhí)行操作 1
if err := tx.Create(&user).Error; err != nil {
    tx.Rollback()  // 錯誤發(fā)生,回滾事務(wù)
    return err
}

// 執(zhí)行操作 2
if err := tx.Model(&user).Update("Age", 30).Error; err != nil {
    tx.Rollback()  // 錯誤發(fā)生,回滾事務(wù)
    return err
}

// 所有操作成功,提交事務(wù)
if err := tx.Commit().Error; err != nil {
    tx.Rollback()  // 提交失敗,回滾事務(wù)
    return err
}

6.6 事務(wù)中的多表操作

在事務(wù)中,你可以操作多個表,只要使用同一個事務(wù)對象 tx,所有的表操作都將在一個事務(wù)內(nèi)完成。

示例:多表操作

tx := db.Begin()

// 插入用戶表
if err := tx.Create(&user).Error; err != nil {
    tx.Rollback()
    return err
}

// 更新訂單表
if err := tx.Model(&order).Update("Status", "Shipped").Error; err != nil {
    tx.Rollback()
    return err
}

// 提交事務(wù)
if err := tx.Commit().Error; err != nil {
    tx.Rollback()
    return err
}
  • 這里插入了一個用戶并更新了訂單狀態(tài),所有操作都在同一個事務(wù)中進行。

6.7 事務(wù)的嵌套

GORM 不直接支持嵌套事務(wù)(即在一個事務(wù)中開啟另一個事務(wù))。但是,你可以通過手動管理事務(wù)嵌套。在嵌套事務(wù)中,只有最外層的事務(wù)會決定是否提交或回滾。

tx := db.Begin()

// 外部事務(wù)操作
if err := tx.Create(&user).Error; err != nil {
    tx.Rollback()
    return err
}

nestedTx := tx.Begin()  // 開始嵌套事務(wù)

// 嵌套事務(wù)操作
if err := nestedTx.Model(&order).Update("Status", "Shipped").Error; err != nil {
    nestedTx.Rollback()  // 嵌套事務(wù)回滾
    tx.Rollback()        // 外部事務(wù)回滾
    return err
}

nestedTx.Commit()  // 嵌套事務(wù)提交

tx.Commit()  // 外部事務(wù)提交
  • 上述代碼演示了如何在一個事務(wù)中手動開啟一個嵌套事務(wù)。嵌套事務(wù)的提交和回滾會影響最外層事務(wù)。

6.8 事務(wù)中的并發(fā)問題

在事務(wù)中使用并發(fā)操作時,必須小心并發(fā)引起的 數(shù)據(jù)競爭 和 死鎖 問題。GORM 默認使用 隔離級別 為 ReadCommitted,你可以通過配置數(shù)據(jù)庫的事務(wù)隔離級別來避免一些并發(fā)問題。

tx := db.Begin().Set("gorm:query_option", "LOCK IN SHARE MODE")

// 事務(wù)操作

此時,LOCK IN SHARE MODE 會在查詢時加鎖,避免其他事務(wù)修改同一行數(shù)據(jù),防止數(shù)據(jù)不一致。

總結(jié)

GORM 是一個功能強大且易于使用的 Go 語言 ORM 庫,能夠讓開發(fā)者以面向?qū)ο蟮姆绞脚c數(shù)據(jù)庫交互,減少了 SQL 語句的編寫和管理的復(fù)雜度。它適合需要處理數(shù)據(jù)庫的 Go 項目,特別是那些涉及大量數(shù)據(jù)操作、需要事務(wù)支持和多表關(guān)聯(lián)的應(yīng)用。

到此這篇關(guān)于GO中GORM 使用教程的文章就介紹到這了,更多相關(guān)GO GORM 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go實現(xiàn)自動解壓縮包以及讀取docx/doc文件內(nèi)容詳解

    Go實現(xiàn)自動解壓縮包以及讀取docx/doc文件內(nèi)容詳解

    在開發(fā)過程中,我們常常需要處理壓縮包和文檔文件。本文將介紹如何使用Go語言自動解壓縮包和讀取docx/doc文件,需要的可以參考一下
    2023-03-03
  • Golang設(shè)計模式中的橋接模式詳細講解

    Golang設(shè)計模式中的橋接模式詳細講解

    橋接模式是一種結(jié)構(gòu)型設(shè)計模式,通過橋接模式可以將抽象部分和它的實現(xiàn)部分分離,本文主要介紹了GoLang橋接模式,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2023-01-01
  • Golang使用singleflight解決并發(fā)重復(fù)請求

    Golang使用singleflight解決并發(fā)重復(fù)請求

    高并發(fā)的場景下,經(jīng)常會出現(xiàn)并發(fā)重復(fù)請求資源的情況,singleflight是golang內(nèi)置的一個包,這個包提供了對重復(fù)函數(shù)調(diào)用的抑制功能,所以下面我們就來看看如何使用它解決并發(fā)重復(fù)請求吧
    2023-08-08
  • Go程序的init函數(shù)在什么時候執(zhí)行

    Go程序的init函數(shù)在什么時候執(zhí)行

    在Go語言中,init?函數(shù)是一個特殊的函數(shù),它用于執(zhí)行程序的初始化任務(wù),本文主要介紹了Go程序的init函數(shù)在什么時候執(zhí)行,感興趣的可以了解一下
    2023-10-10
  • Go語言中字符串四種拼接方式的性能對比

    Go語言中字符串四種拼接方式的性能對比

    在go語言中,字符串是不可變的,因此字符串之間的拼接實際上是創(chuàng)建了一個新的字符串,如果頻繁操作會對性能產(chǎn)生嚴(yán)重的影響,下面我們來看看Go語言中字符串四種常見拼接方式的性能對比吧
    2025-04-04
  • go將request?body綁定到不同的結(jié)構(gòu)體中教程

    go將request?body綁定到不同的結(jié)構(gòu)體中教程

    這篇文章主要為大家介紹了go將request?body綁定到不同的結(jié)構(gòu)體中教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Go errors默認加堆棧信息的作用分析

    Go errors默認加堆棧信息的作用分析

    這篇文章主要為大家介紹了Go errors默認加堆棧信息作用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 詳解Golang Iris框架的基本使用

    詳解Golang Iris框架的基本使用

    這篇文章主要介紹了Golang Iris框架的基本使用,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2020-11-11
  • Golang指針隱式間接引用詳解

    Golang指針隱式間接引用詳解

    在 Go中,指針隱式解引用是指通過指針直接訪問指針?biāo)赶虻闹担恍枰@式地使用 * 運算符來解引用指針,這篇文章主要介紹了Golang指針隱式間接引用,需要的朋友可以參考下
    2023-05-05
  • Ubuntu18.04 LTS搭建GO語言開發(fā)環(huán)境過程解析

    Ubuntu18.04 LTS搭建GO語言開發(fā)環(huán)境過程解析

    這篇文章主要介紹了Ubuntu18.04 LTS搭建GO語言開發(fā)環(huán)境過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11

最新評論