Go语言基础之GORM框架 | 青训营

165 阅读5分钟

青训营笔记6之GORM框架的认识

一、Gorm的基本使用:

GORM 是面向 Golang 语言的一种 ORM(持久层)框架,支持多种数据库的接入支持。例如MySQL、SQLServer、PostgreSQL、SQLite。此框架的特点,弱化了开发者对于 SQL 语言的掌握程度,使用提供的 API 进行底层数据库的访问。

1.1、代码示例

以下是以连接mysql数据库为例

type Product struct { //定义gorm model
  Code string
  Price uint
}   //给model定义表名
func (p Product) TableName() string {
   return "product"        
}
func main() {
     //连接数据库
     db,err := gorm.Open(
         mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
         &gorm.Config{})
     if err !=nil {
       panic("failed to connect database")
     }
     //创建数据
     db.Create(&Product{Code:"D42",Price:100})
     //查询数据
     var product Product
     db.Frist(&product,1)//根据整形主键寻找
     db.Frist(&product,"code = ?","D42")//查找code字段值为D42的记录
     //更新数据,将product的price更新为200
     db.Model(&product).Updates("Price",200)
     //更新多个字段
     db.Model(&product).Updates(Product{Price:200,Code:"F42"})
     db.Model(&product).Updates(map[string]interface{}{"Price":200,"Code":"F42"})
     //删除数据
     db.Delete(&product,1)
 }

注:什么是DSN?

Data Source Name 数据源名称。DSN为ODBC定义了一个确定的数据库和必须用到的ODBC驱动程序。每个ODBC驱动程序定义为该驱动程序支持的一个数据库创建DSN需要的信息。就是说安装ODBC驱动程序以及创建一个数据库之后,必须创建一个DSN。

二、GORM创建数据库

1、如何使用Upsert?

使用clause.OnConflict处理数据冲突

p:=&Product{Code:"D42",ID: 1}
db.Clauses(clause.OnConflict{DoNothing:true}).Create(&p)

2、如何使用默认值?

通过使用default标签为字段定义默认值

type User struct {
   ID int64
   Name string  `gorm:"default:galeone"`
   Age int64 `gorm:"default:18"`
 }

三、GORM查询数据库

First的使用踩坑:

  • 使用First时,需要注意查询不到数据时会返回ErrRecordNotFound.
  • 使用Find查询多条数据,查询不到数据不会返回错误。 使用结构体作为查询条件时: 当使用结构作为条件查询时,GORM只会查询非零值字段。这意味着如果您的字段值为0、"、false或其他零值,该字段不会被用于构建查询条件,使用Map来构建查询条件

四、GORM更新数据库

使用Struct更新时,只会更新非零值,如果需要更新零值,可以使用Map更新或使用Select选择字段

//条件更新单个列
//UPDATE users SET name ='hello' ,updated_at='2013-11-17 21:34:10'WHERE age >18
db.Model(&User{ID:111}).Where("age > ?",18).Update("name","hello")

//更新多个列
//根据`struct`更新属性,只会更新非零值的字段
//UPDATE users SET name='hello',age=18,updated_at = '2013-11-17 21:34:10'WHERE id =111
db.Model(&User{ID:111}).Updates(User{Name:"hello", age:18})

//根据`map`更新属性
//UPDATE users SET name='hello',age=18,actived=false,updated_at = '2013-11-17 21:34:10'WHERE id =111
db.Model(&User{ID:111}).Updates(map[string]interface{}{"name":"hello","age":18,"actived":false})

//更新选定字段
//UPDATE users SET name ='hello' WHERE id =111;
db.Model(&User{ID:111}).Select("name").Updates(map[string]interface{}{"name":"hello","age":18,"actived":false})

//SQL表达式更新
//UPDATE "products" SET "price" = price * 2 + 100,"updated_at"='2013-11-17 21:34:10'WHERE "id" =3;
db.Model(&User{ID:111}).Updates("age",gorm.Expr("age * ? + ?", 2,100))

五、GORM删除数据库

  • 物理删除
db.Delete(&User{},10)//删除id为10的用户
db.Delete(&User{},[]int{1,2,3})//删除id为1,2,3的用户
db.Where("name LIKE ?","%jinzhu%").Delete(User{})//删除名字含有jinzhu的用户
db.Delete(User{},"email LIKE ?","%jinzhu%")//上同
  • 软删除:
  1. GORM提供了gorm.DeleteAt用于用户实现软删
  2. 拥有软删除能力的Model调用Delete时,记录不会被从数据库中真正删除。但GORM会将DeleteAt置为当前时间,并且不能再通过正常的查询方法找到该记录。
  3. 使用Unscoped可以查询到被软删的数据

六、GORM 事务

  • Gorm提供了Begin,Commit,Rollback方法用于使用事务
db,err := gorm.Open(
         mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
         &gorm.Config{})
 if err !=nil {
     panic("failed to connect database")
 }
 tx := db.Begin()  //开始事务
 //在事务中执行一些db操作
 if err = tx.Create(&User{Name:"name"}).Error; err != nil {
    tx.Rollback()//遇到错误时回滚事务
    return
 }
 if err =tx.Create(&User{Name:"name1"}).Error; err != nil {
    tx.Rollback()
    return
 }
 //提交事务
 tx.Commit()
  • Gorm提供了Tansaction方法用于自动提交事务,避免用户漏写Commit,Rollback。
db,err := gorm.Open(
         mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
         &gorm.Config{})
     if err !=nil {
       panic("failed to connect database")
     }
     if err = db.Transaction(func(tx *gorm.DB) error {
        if err tx.Create(&User{Name:"name"}).Error; err!= nil {
            return err
        }
        if err =tx.Create(&User{Name: "name1"}).Error; err!=nil {
            tx.Rollback()
            return err
        }
        return nil
     });err!=nil {
        return
     }

七、GORM Hook

GORM提供了CURD的Hook能力,Hook是在创建、查询、更新、删除等操作之前、之后自动调用的函数。如果任何Hook返回错误,GORM将停止后续的操作并回滚事务。

type User struct {
   ID int64
   Name string  `gorm:"default:galeone"`
   Age int64 `gorm:"default:18"`
 }
 type Email struct {
   ID int64
   Name string
   Email string
 }
 func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
    if u.Age < 0 {
         return errors.New("can't save invaild data")
    }
    return 
 }
 func (u *User) AfterCreate(tx *gorm.Db) (erer error) {
   return tx.Create(&Email{ID: u.ID, Email: u.Name + "@***.com"}).Error
 }

八、GORM性能提高

  • 对于写操作(创建、更新、删除),为了确保数据的完整性,GORM会将它们封装在事务内运行。但这会降低性能,你可以使用 SkipDefaultTransation关闭默认事务。

  • 使用PrepareStmt缓存预编译语句可以提高后续调用的速度,本机测试提高大约三成

db,err := gorm.Open(
         mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
         &gorm.Config{
         SkipDefaultTransation:true,//关闭默认事务
         PrepareStmt:          true},//缓存预编译语句
 )
 if err !=nil {
     panic("failed to connect database")
 }