在CSDN学Golang工程组件(对象关系映射gorm)

一,Model的定义与tag的使用

在Golang中,Model的定义通常是通过结构体(struct)来实现的。开发者可以通过定义一个struct类型,并在其中定义多个字段(field)来创建一个Model。

例如:

type User struct {
    ID       int64
    Name     string
    Age      int
    Address  string
}

上面的代码定义了一个名为User的Model,它包含四个字段:ID、Name、Age和Address。

除了结构体本身之外,还可以使用tag标签来给每个字段添加元数据信息。这些标签以键值对的形式出现在每个字段后面,以逗号分隔。常见的用途包括序列化、反序列化、验证等。

例如:

type User struct {
    ID       int64   `json:"id"`
    Name     string  `json:"name"`
    Age      int     `json:"age"`
    Address  string  `json:"address,omitempty"`
}

上述代码为User Model中的每个字段都添加了json标签。这意味着当使用JSON序列化时,ID将被转换为"id"键值对应的值;同样地,Name和Age也会被转换为相应的键值对。注意到Address加入了omitempty选项,则表示当Address为空时不进行JSON序列化操作。在Golang中,我们可以通过结构体和tag标签来定义并描述自己所需要的Model类型,并方便地完成各种数据处理操作。

二,基于orm的CRUD与原生SQL

在Golang中,使用ORM(对象关系映射)框架可以方便地进行CRUD(创建、读取、更新和删除)操作。常用的ORM框架包括Gorm、Xorm等。

以下是基于Gorm框架进行CRUD操作的示例:

  1. 创建记录
user := User{Name: "Bob", Age: 18}
db.Create(&user)
  1. 查询记录
var users []User
db.Find(&users)
  1. 更新记录
db.Model(&user).Update("Age", 20)
  1. 删除记录
db.Delete(&user)

除了ORM框架之外,开发者也可以使用原生SQL语句来执行数据库操作。这通常需要使用数据库驱动程序和连接池来建立与数据库的连接,并通过预编译语句来提高性能。

以下是一个基于Go内置的database/sql库进行原生SQL解析的示例:

  1. 建立数据库连接
import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8")
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()
}
  1. 执行查询语句并获取结果
rows, err := db.Query("SELECT * FROM users WHERE age > ?", 18)
if err != nil {
    panic(err.Error())
}
defer rows.Close()

for rows.Next() {
    var id int
    var name string
    var age int
    var address string

    err := rows.Scan(&id, &name, &age, &address)
    if err != nil {
        panic(err.Error())
    }
}
  1. 执行更新语句
stmt, err := db.Prepare("UPDATE users SET age = ? WHERE id = ?")
if err != nil {
    panic(err.Error())
}
defer stmt.Close()

result, err := stmt.Exec(20, 1)
if err != nil {
    panic(err.Error())
}

rowsAffected, _ := result.RowsAffected()
fmt.Println(rowsAffected)

在Golang中,开发者可以选择使用ORM框架或原生SQL语句来执行数据库操作。ORM框架通常更易于使用和维护,而原生SQL语句则更灵活和可定制化。

三,嵌套事务,SavePoint/RollbackTo事务

在Golang中,可以使用数据库事务来确保一组操作要么全部成功,要么全部失败回滚。但是,在某些情况下,我们需要进行更细粒度的事务控制,例如在一个大的事务内嵌套多个小的事务。这时候可以使用SavePoint和RollbackTo等机制来实现。

SavePoint是指定在当前事务中创建的一个保存点。通过创建保存点,我们可以将当前事务分成多个独立的部分,并且每个部分都具有其自己的回滚段。

RollbackTo则是撤销到之前指定的保存点,并将所有后续更改回滚到该点。这使得我们可以针对特定代码块内发生的错误或异常进行回滚,而不必回滚整个事务。

以下是一个基于Gorm框架和MySQL数据库进行嵌套事务、SavePoint和RollbackTo实现的示例:

// 定义User结构体
type User struct {
    ID   int
    Name string `gorm:"not null"`
    Age  int
}

// 创建外层事务
func (db *DB) OuterTransaction() error {
    tx := db.Begin()

    // 在外层事务中创建一个保存点sp1
    if err := tx.Exec("SAVEPOINT sp1").Error; err != nil {
        tx.Rollback()
        return err
    }

    // 创建内层第一个子事务并插入数据
    if err := db.insertUser(tx, &User{Name: "Alice", Age: 18}); err != nil {
        // 回滚到保存点sp1
        if err := tx.Exec("ROLLBACK TO sp1").Error; err != nil {
            tx.Rollback()
            return err
        }
    }

    // 创建内层第二个子事务并插入数据
    if err := db.insertUser(tx, &User{Name: "Bob", Age: 20}); err != nil {
        // 回滚到保存点sp1
        if err := tx.Exec("ROLLBACK TO sp1").Error; err != nil {
            tx.Rollback()
            return err
        }
    }

    // 提交外层事务
    return tx.Commit().Error
}

// 插入用户数据的函数,接收一个事务和要插入的用户对象作为参数
func (db *DB) insertUser(tx *gorm.DB, user *User) error {
    // 在当前事务中创建一个新的保存点sp2
    if err := tx.Exec("SAVEPOINT sp2").Error; err != nil {
        return err
    }

    // 向数据库中插入用户数据
    if result := tx.Create(user); result.Error != nil {
        // 回滚到保存点sp2,撤销所有后续更改(例如删除、更新等)
        if err := tx.Exec("ROLLBACK TO sp2").Error; err != nil {
            return err
        }
        return result.Error
    }

    // 返回nil表示没有错误发生,可以提交该子事务的更改。
    return nil 
}

在上面的示例中,我们使用了两个嵌套的事务。外层事务包含两个内层子事务,每个子事务都使用了SavePoint和RollbackTo机制。如果任何一个子事务出现错误,我们将回滚到保存点并撤销所有后续更改。在Golang中,嵌套事务、SavePoint和RollbackTo等机制可以帮助我们进行更精细的事务控制。这些机制在处理复杂的业务逻辑时非常有用,但同时也需要注意确保正确处理错误和异常情况。

四,Hook与Session

在Golang中,Hook和Session是Gorm框架提供的两个非常重要的功能。它们可以用来在执行数据库操作时进行拦截和处理,并且可以自定义一些行为以满足特定需求。

  1. Hook

Hook是一个钩子函数,它允许我们在执行某些数据库操作之前或之后进行拦截和处理。Gorm框架提供了多种类型的Hook,例如BeforeCreate、AfterUpdate、BeforeDelete等等。通过实现这些Hook函数,我们可以在操作数据库前后做一些特定的逻辑处理。

以下是一个示例代码:

// 定义User结构体
type User struct {
    ID   int
    Name string `gorm:"not null"`
    Age  int
}

// 实现BeforeCreate Hook函数,在插入数据前将Age字段设置为18
func (u *User) BeforeCreate(tx *gorm.DB) error {
    u.Age = 18
    return nil
}

// 创建用户对象并插入到数据库中
func CreateUser(db *gorm.DB, name string) error {
    user := &User{Name: name}
    if err := db.Create(user).Error; err != nil {
        return err
    }
    return nil
}

在上面的示例中,我们定义了一个User结构体和一个BeforeCreate Hook函数。该函数会在插入数据之前被调用,并将Age字段设置为18。当我们调用CreateUser方法创建新用户时,会自动触发BeforeCreate Hook函数,并根据定义对Age字段进行修改。

  1. Session

Session是Gorm框架提供的一个非常强大的功能,它可以用来实现复杂的数据库操作。通过创建Session对象,我们可以在单个事务中执行多次数据库操作,并保证所有操作要么全部成功,要么全部失败回滚。

以下是一个示例代码:

// 定义User结构体
type User struct {
    ID   int
    Name string `gorm:"not null"`
    Age  int
}

// 创建用户对象并插入到数据库中,使用Session保证事务性
func CreateUser(db *gorm.DB, name string) error {
    user := &User{Name: name}
    
    // 开始一个新的Session对象
    tx := db.Begin()
    
    // 在Session中插入用户数据
    if err := tx.Create(user).Error; err != nil {
        // 如果出错则回滚整个事务
        tx.Rollback()
        return err
    }

    // 更新用户年龄字段为20岁
    if result := tx.Model(user).Update("Age", 20); result.Error != nil {
        // 如果出错则回滚整个事务
        tx.Rollback()
        return result.Error
    }
    
    // 提交事务并返回nil表示没有错误发生
    return tx.Commit().Error 
}

在上面的示例中,我们定义了一个CreateUser函数,并使用Session对象来保证插入和更新操作在同一事务内进行。如果任何一个操作出错,则会自动回滚整个事务。在Golang中,Hook和Session是两个非常有用的功能。通过实现Hook函数,我们可以在数据库操作前后进行拦截和处理,并实现一些特定的逻辑;而通过创建Session对象,我们可以保证多个数据库操作在同一事务内执行,并确保所有操作要么全部成功,要么全部失败回滚。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值