Golang GORM实战(一) | 快速安装与入门

2022年4月8日 369点热度 0人点赞 0条评论

GORM是一个非常优秀的Golang数据库ORM库,支持MySQL, PostgreSQL, SQlite, SQL Server等数据库,目前在Github有接近2.8万个star,足见其优秀与受欢迎的程度。

database/sql

database/sql库是Go内置的用于操作数据库的标准库,在使用Go开发需要操作数据库的项目时,在不引入第三方库的情况下,可以完成对数据库的操作,下面我们通过一个示例来了解一下:

package main

import (
 "database/sql"
 "fmt"

 _ "github.com/go-sql-driver/mysql"
)

//操作数据库的对象
var db *sql.DB

//数据表模型
type User struct {
 ID   int
 Name string
 Age  int
}

func main() {

 var err error
 //打开数据库连接
 db, err = sql.Open("mysql""root:123456@tcp(localhost:3306)/test?charset=utf8&parseTime=True&loc=Local")
 if err != nil {
  panic(err)
 }
 if err = db.Ping(); err != nil {
  panic(err)
 }
 defer db.Close() //关闭数据库

 if Insert(&User{ID: 1, Name: "aaaaaa", Age: 20}) > 0 {
  fmt.Println("用户1写入成功")
 }
 if Insert(&User{ID: 2, Name: "bbbbbb", Age: 21}) > 0 {
  fmt.Println("用户2写入成功")
 }

 //查询单条数据
 u := QueryOne(1)
 fmt.Println(u.ID, u.Name, u.Age)
 //查询全表数据
 fmt.Println(QueryAll())

 //更新
 if Update(&User{ID: 1, Name: "cccccc", Age: 30}) > 0 {
  fmt.Println("用户1信息更新成功")
 }
 fmt.Println(QueryOne(1))

 //删除
 if Delete(1) {
  fmt.Println("用户1删除成功")
 }
 if Delete(2) {
  fmt.Println("用户2删除成功")
 }
 fmt.Println(QueryOne(1))
 fmt.Println(QueryOne(2))
}

func QueryAll() []*User {
 rows, _ := db.Query("SELECT * FROM users")
 defer rows.Close()
 var users []*User
 for rows.Next() {
  var user = &User{}
  _ = rows.Scan(&user.ID, &user.Name, &user.Age)
  users = append(users, user)
 }
 return users
}

func QueryOne(id int) *User {
 rows, _ := db.Query("SELECT * FROM users WHERE id = ?", id)
 defer rows.Close()
 var user *User
 for rows.Next() {
  user = &User{}
  _ = rows.Scan(&user.ID, &user.Name, &user.Age)
 }
 return user
}

func Delete(id int) bool {
 //删
 rsDelete, err := db.Exec("DELETE FROM users WHERE id = ?", id)
 if err != nil {
  return false
 }
 n, err := rsDelete.RowsAffected()
 if err != nil {
  return false
 }
 return n > 0
}

func Update(user *User) int64 {
 //改
 rsUpdate, err := db.Exec("UPDATE users SET name = ?,age = ? WHERE id = ?", user.Name, user.Age, user.ID)

 if err != nil {
  return 0
 }
 n, err := rsUpdate.RowsAffected()
 if err != nil {
  return 0
 }
 return n
}

func Insert(user *User) int64 {
 //增
 rsInsert, err := db.Exec("INSERT INTO users values(?,?,?)", user.ID, user.Name, user.Age)

 if err != nil {
  return 0
 }
 n, err := rsInsert.RowsAffected()
 if err != nil {
  return 0
 }
 return n
}

从上面的例子中,我们可以看出使用database/sql标准库操作数据库有两个缺点:

  1. 不能将模型映对为数据表的操作,需要自己写SQL语句

  2. 不能将查询结果集映射到数据模型中,需要自己遍历

对于小项目来说,全部自己写SQL和自己遍历查询结果集,也是可以接受的,但如果是大项目的话,上面两个问题会导致项目越来越难维护。

这时候,使用ORM库可以帮我们完美解决上述的问题,而GORM无疑是首选。

GORM

GORM是一个对Go开发者非常友好的ORM库,上手非常简单,在GORM的官网文档上,我们可以看见其列出了GORM的以下特性:

  • 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
  • Create,Save,Update,Delete,Find 中钩子方法
  • 支持 Preload、Joins 的预加载
  • 事务,嵌套事务,Save Point,Rollback To Saved Point
  • Context、预编译模式、DryRun 模式
  • 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进行 CRUD
  • SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
  • 复合主键,索引,约束
  • Auto Migration
  • 自定义 Logger
  • 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…

上面列举的GORM特性非常之多,我们也将在《Golang GORM实战》这个系列中一起学习,慢慢探究与学习GORM的功能与特性,掌握GORM的使用及其原理。

GORM安装与其第三方库安装方式是一样的,非常简单:

  1. 安装gorm库
go get -u gorm.io/gorm
  1. 安装对应数据库的驱动
# sqlite
go get -u gorm.io/driver/sqlite

# mysql
go get -u gorm.io/driver/mysql

# postgres
go get -u gorm.io/driver/postgres

# sqlserver
go get -u gorm.io/driver/sqlserver

根据你想要访问的数据库,安装对应的驱动即可。

其实如果你细心留意的话,在上面使用database/sql的例子中,也需要安装驱动,在上面的例子中,你可以看下面的代码:

import (
 "database/sql"
 "fmt"

 _ "github.com/go-sql-driver/mysql"
)

其中github.com/go-sql-driver/mysql库便是使用database/sql库访问mysql的驱动。

驱动层才是直接帮我们去访问的数据库的地方,而gorm库和database/sql这两个库只是在驱动层之上再封装一层,提供统一访问层,这样之后如果我们想更换数据库,比如从mysql切换到sqlserver,只需要改下引入的驱动库,而不是修改任何操作数据库的代码,访问层、驱动层与数据库,如下图所示:

图片
image.png

我们将上面的示例用GROM重写一次,如下:

package main

import (
 "fmt"

 "gorm.io/driver/mysql"
 "gorm.io/gorm"
)

type User struct {
 ID   int
 Name string
 Age  int
}

func main() {
 dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"
 db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) //打开数据库连接
 if err != nil {
  panic(err)
 }
 DB, _ := db.DB()
 defer DB.Close() //在函数执行完成后关闭数据库句柄

 //新增
 rsOne := db.Create(&User{ID: 1, Name: "aaaaaaaaaa", Age: 32})
 if rsOne.RowsAffected > 0 {
  fmt.Println("用户1创建成功")
 }

 rsTwo := db.Create(&User{ID: 2, Name: "bbbbb", Age: 32})
 if rsTwo.RowsAffected > 0 {
  fmt.Println("用户2创建成功")
 }

 //查询
 var u1 User
 db.Find(&u1, "id = ?", 1)
 fmt.Println(u1)

 //批量查询
 var users []User
 db.Find(&users)
 fmt.Println(users)

 //修改
 u1.Name = "11111111"
 rsSave := db.Save(u1)
 if rsSave.RowsAffected > 0 {
  fmt.Println("用户创建成功")
 }
 //修改后查询数据是否已经变化
 db.Find(&u1, "id = ?", 4)
 fmt.Println(u1)

 //删除
 rsDelete := db.Delete(u1)
 if rsDelete.RowsAffected > 0 {
  fmt.Println("用户删除成功")
 }
}

小结

本篇是《Golang GORM实战》的第一篇文章,我们对比了database/sql与GROM的使用,知道了database/sql的局限性,也清楚GORM的便利性,既然GORM对于我们数据库应用如此便利,那么就有必要在后续中更加深入地学习,因此更多的关于GORM库的知识,笔者也会这个系列中持续更新,欢迎学习,文章不正确的地方,也欢迎指正,先行感谢!

13360Golang GORM实战(一) | 快速安装与入门

root

这个人很懒,什么都没留下

文章评论