gorm初探 | 青训营

165 阅读4分钟

一、gorm 简介

1. 什么是 orm ?

orm,Object-Relationl Mapping,即对象关系映射,这里的Relationl指的是关系型数据库。它的作用是将对象与数据库关联起来,这样我们在操作数据库的时候不需要手写繁杂的sql语句,只需要调用对应的方法就可以起到一样的作用,本质上是为了简化数据库操作或是统一数据库操作诞生的。因为你有可能会使用不同的数据库,如 MySQL、SQL Server、 MongoDB等等,这些数据库的SQL语言在使用方面有一些细小的区别,通过orm,可以用一个统一的语言 API,来处理这些不同的数据库。

2. 什么是 gorm ?

自然是用 Go 语言写的一个 orm 框架

二、gorm 简单使用

gorm有很多复杂操作,这里只是简单介绍一下常规使用方法。

1. gorm 安装

go get -u github.com/jinzhu/gorm
go get -u github.com/go-sql-driver/mysql

第一行导入 gorm 的包
第二行导入 mysql 的驱动

2. 连接数据库

gorm不具备创建数据库的能力,你只能自己手动创建一个数据库,然后使用 gorm 去连接

var db *gorm.DB

func init() {  
    username := "root"  
    password := "root"  
    host := "127.0.0.1"  
    port := 3306  
    Dbname := "gorm"  
    //timeout := "10s"  
  
    s := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username, password, host, port, Dbname)  
    db, _ = gorm.Open(mysql.Open(s), &gorm.Config{  
        NamingStrategy: schema.NamingStrategy{  
            TablePrefix: "f_",  
            SingularTable: true,  
            NoLowerCase: false,  
        },  
    })  
}

这是连接 mysql 的格式,不同数据库的连接字符串格式不同。在连接数据库时,gorm 可以额外添加配置,在第二个参数 gorm.Config 结构体内增加参数,结构体参数非常多,不一一列举,可以去官网参考。

https://gorm.io/zh_CN/docs/index.html

这里列举几个比较实用的。在 NamingStrategy 这个字段中定义的是命名规则的约束,在这个字段中,TablePrefix 是表名的前缀,创建表会自动添加前缀,SingularTable 是表名单数,默认是表名以复数形式,NoLowerCase 是不做小写转换。

3. 建表

type User struct {
    gorm.Model
    Name        string      `gorm:"size:50"`
    Age         int         `gorm:"size:3"`
    Birthday    *time.Time
    Email       string      `gorm:"type:varchar(50);unique_index"`
    PassWord    string      `gorm:"type:varchar(25)"`
}

func mian() {
    gorm.AutoMigrate(&User{})
}

main 函数中的这个方法是自动迁移,也就是自动建表并更新表结构,但它不会删除或修改已有的列,只能增加新列。gorm 默认将字段名为 ID 的字段设为主键,这里的 ID 字段嵌套在了 gorm.Model 中,这是一个 gorm 提供的默认结构,里面定义了 ID、创建时间、删除时间等字段。

type Model struct {
    ID        uint           `gorm:"primaryKey"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt gorm.DeletedAt `gorm:"index"`
}

另外,结构体的 tag 可以指定表属性的类型和一些参数就像上文的 User 结构体那样。

4. 插入数据

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}

result := db.Create(&user) // 通过数据的指针来创建

user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数

也可以往 Create 函数里传一个切片,一次插入多条数据

db.Model(&User{}).Create(map[string]interface{}{
  "Name": "jinzhu", "Age": 18,
})

// batch insert from `[]map[string]interface{}{}`
db.Model(&User{}).Create([]map[string]interface{}{
  {"Name": "jinzhu_1", "Age": 18},
  {"Name": "jinzhu_2", "Age": 20},
})

还可以使用 map 插入,但是前面要加上 Model 指定表。

5. 查询数据

// 获取第一条记录(主键升序)  
db.First(&user)  
// SELECT * FROM users ORDER BY id LIMIT 1;  
  
// 获取一条记录,没有指定排序字段  
db.Take(&user)  
// SELECT * FROM users LIMIT 1;  
  
// 获取最后一条记录(主键降序)  
db.Last(&user)  
// SELECT * FROM users ORDER BY id DESC LIMIT 1;  
  
result := db.First(&user)  
result.RowsAffected // 返回找到的记录数  
result.Error // returns error or nil  
  
// 检查 ErrRecordNotFound 错误  
errors.Is(result.Error, gorm.ErrRecordNotFound)

都是将获得的数据存入 user 变量中。使用结构体是零值的字段会被忽略,使用 map 时,零值字段会被保留。

6. 高级查询

db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&orders) 
// SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders");  

subQuery := db.Select("AVG(age)").Where("name LIKE ?", "name%").Table("users") 
db.Select("AVG(age) as avgage").Group("name").Having("AVG(age) > (?)", subQuery).Find(&results) 

// SELECT AVG(age) as avgage FROM `users` GROUP BY `name` HAVING AVG(age) > (SELECT AVG(age) FROM `users` WHERE name LIKE "name%") 

子查询的使用方法,和原生 SQL 差不多的语法。

7. 更新

更新多列

db.First(&user)  
  
user.Name = "jinzhu 2"  
user.Age = 100  
db.Save(&user)  
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

Save 方法会保存所有字段,哪怕字段是零值

更新单个列

// Update with conditions
db.Model(&User{}).Where("active = ?", true).Update("name", "hello") 
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

// User's ID is `111`: 
db.Model(&user).Update("name", "hello") 
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

// Update with conditions and model value 
db.Model(&user).Where("active = ?", true).Update("name", "hello") 
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true; 

8. 删除

db.Delete(&User{}, 10)  
// DELETE FROM users WHERE id = 10;  
  
db.Delete(&User{}, "10")  
// DELETE FROM users WHERE id = 10;  
  
db.Delete(&users, []int{1,2,3})  
// DELETE FROM users WHERE id IN (1,2,3);

根据主键删除。另外 gorm 的删除并不是物理删除,他只是将 Model 结构中的删除时间更新,这样来做到逻辑删除,来保护数据库数据。