Database/sql及GORM|青训营笔记

73 阅读3分钟

这是我参与「第五届青训营」伴学笔记创作活动的第6天

1 理解database/sql

1、基本用法

import (
   "database/sql"
)

func main() {
   // 使用driver+DSN初始化DB链接
   db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
   // 执行SQL语句,通过rows取返回的数据
   rows, err := db.Query("select id, name from users where id = ?", 1)
   if err != nil {

   }
   // 处理完毕,释放连接
   defer rows.Close()

   // 数据和错误处理
   var users []User
   for rows.Next() {
      var user User
      err := rows.Scan(&user.ID, &user.Name)
      if err != nil {

      }
      users = append(users, user)
   }
   // 错误处理
   if rows.Err() != nil {
      
   }
}

2、设计原理

image-20230201100235224.png

在中间的database/sql层中,会对连接池进行操作,为了建立与数据库新的连接,可以直接从连接池中复用已存在的连接,或者直接新建新的连接,当当前连接使用完后,还会放回到连接池中defer dc.db.putConn(dc,err,true)

2 GORM

go get时出现问题:

go get -u github.com/jinzhu/gorm

go: module github.com/jinzhu/gorm: Get "https://proxy.golang.org/github.com/jinzhu/gorm/@v/list": dial tcp 142.251.43.17:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

解决办法:配置代理 go env -w GOPROXY=https://goproxy.cn

1、基本用法

连接数据库

import (
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
)
func main() {
	db, err := gorm.Open(mysql.Open("user:password@tcp(127.0.0.1:3306)/3306"))

	var users []User
	err := db.Select("id", "name").Find(&users, 1).Error
}

CRUD

// 操作数据库
db.AutoMigrate(&Product{})
db.Migrator().CreateTable(&Product{})
// 创建
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
result := db.Create(&user)
// 返回主键、error、影响的行数
user.ID
result.Error
result.RowsAffected
// 批量创建
var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}}
db.Create(&user)
db.CreateInBatches(users, 100)
for _, user := range users {
   user.ID
}

// 读取
var product Product
db.First(&product, 1)
db.First(&product, "code = ?", "L1212")

result := db.Find(&users, []int{1, 2, 3})
result.RowsAffected                             // 返回找到的记录数
errors.Is(result.Error, gorm.ErrRecordNotFound) // First Last Take查不到数据
// 更新某个字段
db.Model(&product).Update("price", 2000)
db.Model(&product).UpdateColumn("Price", 2000)
// 更新多个字段
db.Model(&product).Updates(Product{Price: 2000, Code: "L1212"})
db.Model(&product).Updates(map[string]interface{}{"Price": 2000, "Code": "L1212"})
// 批量更新
db.Model(&Product{}).Where("price < ?", 2000).Updates(map[string]interface{}{"price": 2000})
// 删除
db.Delete(&product)

关联

1、关联操作CRUD

// 保存用户及关联
db.Save(&User {
   Name: "jinzhu",
   Languages: []Language{{Name: "zh-CN"}, {Name: "en-US"}},
})
// 关联模式
langAssociation := db.Model(&user).Association("Languages")
// 查询关联
langAssociation.Find(&langAssociation)
langAssociation.Append([]Language{languageZH, languageEN})
langAssociation.Replace([]language{languageZH, languageDE})
langAssociation.Delete(languageZh, langugeEN)
langAssociation.Clear()
langAssociation.Count()

// 批量模式
var users []User{user1, user2, user3}
langAssociation := db.Model(&users).Association("Languages")
db.Model(&users).Association("Team").Append(&userA, userB, &[]User{UserA, UserB})

2、Preload、Joins预加载

// 查询用户时找出其他订单,个人信息
db.Preload("Orders").Preload("Profile").Find(&users)
// 使用Join SQL加载
db.Joins("Company").Joins("Manager").First(&user, 1)
db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users)
// 预加载全部关联
db.Preload(clause.Associations).Find(&users)
// 多级预加载
db.Preload("Orders.OrderItems.Product").Find(&users)
db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)
// 查询用户时找出未取消的订单
db.Preload("Orsers", "state NOT IN(?)", "cancelled").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)

db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
   return db.Order("orders.amount DESC")
}).Find(&users)

3、级联删除

// 方法1.使用数据库约束自动删除
// 需要使用GORM Migrate数据库迁移数据库外键
db.AutoMigrate(&User{})
// 如果未启用软删除,再删除User时会自动删除其依赖
db.Delete(&User{})
// 方法2:使用Select实现级联删除,不依赖数据库约束及软删除
db.Select("Account").Delete(&user)
db.Select("Orders", "CreditCards").Delete(&user)
db.Select(clause.Associations).Delete(&user)

2、设计原理

image-20230202112003236.png 3、最佳实践

  • 数据序列化与SQL表达式
  • 批量数据操作
  • 代码复用、分库分表、Sharding
  • 混沌工程
  • Logger/Trace
  • Migrator
  • Gen代码生成/Raw SQL
  • 安全