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

GO中GORM 使用教程

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

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

1. 安裝 GORM

首先,你需要安裝 GORM 庫(kù)。打開(kāi)終端并運(yùn)行以下命令:

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

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

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

package main

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

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

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

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

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

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

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

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

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

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

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

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

4.1 創(chuàng)建記錄

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

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) 使用 & 符號(hào)是因?yàn)槲覀円獋鬟f結(jié)構(gòu)體 user 的 指針 給 Create 方法。具體來(lái)說(shuō),這樣做有以下幾個(gè)原因:

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

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

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

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

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

  • GORM 的工作方式

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

4.2 查詢記錄

GORM 提供了多種查詢方式,可以通過(guò)結(jié)構(gòu)體查詢、條件查詢等方式來(lái)獲取數(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 提供的一個(gè)查詢方法,用于從數(shù)據(jù)庫(kù)中獲取 第一條 滿足條件的記錄。它通常用于根據(jù)主鍵或其他條件查詢數(shù)據(jù)。

db.First 的基本語(yǔ)法:

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

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

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

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

獲取多個(gè)記錄

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 提供的查詢方法之一,用于查找多個(gè)記錄并將其存儲(chǔ)到傳入的切片結(jié)構(gòu)體中。

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

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

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

Find 方法的其他功能

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

這個(gè)查詢會(huì)返回所有年齡大于 30 的用戶。

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

4.3 更新記錄

在 GORM 中,更新記錄是一個(gè)常見(jiàn)的操作。你可以通過(guò) GORM 提供的幾種方法來(lái)更新記錄。以下將詳細(xì)介紹 GORM 中更新記錄的方式,包含基本更新、部分更新、批量更新等操作,并解釋每種方法的具體用法和注意事項(xiàng)。

基本更新:db.Save 方法

db.Save 方法用于保存(或更新)結(jié)構(gòu)體中的數(shù)據(jù)。如果結(jié)構(gòu)體的主鍵已經(jīng)存在,GORM 會(huì)執(zhí)行 更新操作;如果主鍵不存在,GORM 會(huì)執(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) 會(huì)檢查 user 是否已有主鍵值(假設(shè)主鍵存在)。如果存在,它將執(zhí)行更新操作,將 user 結(jié)構(gòu)體中修改的字段更新到數(shù)據(jù)庫(kù)中。
  • 如果主鍵不存在,它會(huì)將 user 插入到數(shù)據(jù)庫(kù)中。

注意:

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

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

db.Updates 方法允許你更新結(jié)構(gòu)體中的 部分字段,而不是全部字段。它是一個(gè)更精確的更新方法,通常用于僅更新結(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})
}

在這個(gè)例子中:

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

注意:

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

單個(gè)字段更新:db.Update 方法

如果你只需要更新某個(gè)單獨(dú)的字段,可以使用 db.Update 方法。該方法用于 更新單個(gè)字段,是 db.Updates 的簡(jiǎn)化版本,適合只更新單一字段的場(chǎng)景。

示例

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

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

注意:

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

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

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

UpdateColumn 示例

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

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

UpdateColumns 示例

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

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

注意:

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

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

你可以在更新時(shí)通過(guò) Where 方法指定更新的條件。Where 方法可以與 Updates 或 Update 一起使用,以便進(jìn)行條件更新。

示例

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

注意:

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

批量更新(多個(gè)記錄)

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

示例

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

注意:

  • Updates 會(huì)更新所有符合條件的記錄,而不是只更新一個(gè)記錄。

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

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

示例

tx := db.Begin()

// 執(zhí)行多個(gè)更新操作
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() 開(kāi)始一個(gè)事務(wù)。
  • tx.Commit() 提交事務(wù),tx.Rollback() 在出錯(cuò)時(shí)回滾事務(wù),確保所有操作的原子性。

4.4 刪除記錄

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

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

    // 刪除用戶
    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)系。一個(gè)用戶可以有多個(gè)帖子,可以使用 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 兩個(gè)表,你可以使用 Preload 來(lái)加載關(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)你插入一個(gè)帶有關(guān)聯(lián)的記錄時(shí),可以使用 Create 方法來(lái)同時(shí)插入主表和從表數(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) 是一個(gè)非常重要的概念,尤其是在需要確保多個(gè)數(shù)據(jù)庫(kù)操作要么全部成功,要么全部失敗的情況下。事務(wù)能夠保證操作的原子性、一致性、隔離性和持久性(即 ACID 特性)。如果在事務(wù)中的某個(gè)操作失敗,事務(wù)可以回滾,使得數(shù)據(jù)庫(kù)回到事務(wù)開(kāi)始之前的狀態(tài)。

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

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

在 GORM 中,你可以通過(guò) db.Begin() 來(lái)啟動(dòng)一個(gè)事務(wù),使用 tx.Commit() 來(lái)提交事務(wù),使用 tx.Rollback() 來(lái)回滾事務(wù)。以下是 GORM 中事務(wù)的常見(jiàn)用法。

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

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

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

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

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

示例

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

// 執(zhí)行多個(gè)數(shù)據(jù)庫(kù)操作
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) 會(huì)在事務(wù)中插入一條記錄。
  • tx.Model(&user).Update("Age", 30) 會(huì)在事務(wù)中更新該記錄。

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

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

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

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

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

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

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

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

tx := db.Begin()

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

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

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

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

在事務(wù)中,你可以操作多個(gè)表,只要使用同一個(gè)事務(wù)對(duì)象 tx,所有的表操作都將在一個(gè)事務(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
}
  • 這里插入了一個(gè)用戶并更新了訂單狀態(tài),所有操作都在同一個(gè)事務(wù)中進(jìn)行。

6.7 事務(wù)的嵌套

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

tx := db.Begin()

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

nestedTx := tx.Begin()  // 開(kāi)始嵌套事務(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ù)提交
  • 上述代碼演示了如何在一個(gè)事務(wù)中手動(dòng)開(kāi)啟一個(gè)嵌套事務(wù)。嵌套事務(wù)的提交和回滾會(huì)影響最外層事務(wù)。

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

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

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

// 事務(wù)操作

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

總結(jié)

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

    Go語(yǔ)言中字符串四種拼接方式的性能對(duì)比

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

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

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

    Go errors默認(rèn)加堆棧信息的作用分析

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

    詳解Golang Iris框架的基本使用

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

    Golang指針隱式間接引用詳解

    在 Go中,指針隱式解引用是指通過(guò)指針直接訪問(wèn)指針?biāo)赶虻闹?,而不需要顯式地使用 * 運(yùn)算符來(lái)解引用指針,這篇文章主要介紹了Golang指針隱式間接引用,需要的朋友可以參考下
    2023-05-05
  • Ubuntu18.04 LTS搭建GO語(yǔ)言開(kāi)發(fā)環(huán)境過(guò)程解析

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

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

最新評(píng)論