【GO 数据库 | 青训营笔记】

106 阅读4分钟

这是我参与【第五届青训营】伴学笔记创作活动的第四天,此篇概述一下在青训营学习的go语言的数据库有关的知识。

image.png

Datebase/sql

1.png

  1. 基本用法:

    • 数据库连接:

      db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/hello")
      
    • 数据库查询:

      rows, err := db.Query("select id,name from users where id = ?", 1)
      if err != nil { 
          // xxx
      }
      defer func() { // 后关闭,避免信息泄露
          err = rows.Close()
          if err != nil {}
      }   
      var users []user     // 存储查询的结果
      for rows.Next() {
          var user User
          err := rows.Scan(&user.Id, &user.Name)
          if err != nil { 
              // xxx
          }
          users = append(users, user)  
      }
      if rows.Err() != nil {  
          // ...
      }
      
  2. Driver 连接接口

    // Driver接口
    type Driver interface {
        // Open returns a new connection to the database.
        Open(name string) (Conn,error)
    }
    ​
    ​
    // Register makes a database driver available by the provided name.
    // If Register is called twice with the same name or if driver is nil,
    // it panics.
    func Register(name string,driver driver.Driver) {
        driversMu. Lock()
        defer driversMu.Unlock()
        if driver = nil {
            panic( "sql: Register driver is nil")
        }
        if _, dup := drivers[name]; dup {
            panic("sql: Register called twice for driver " + name)
        }
        drivers[name] = driver
    }
    ​
    // github . com/go-sql-driver/mysql/driver.go
    // 注册Driver
    func init {
        sql.Register("mysql",&MySQLDriver{})
    }
    ​
    ​
    type Conn interface {
        // 返回与当前连接相关的执行SQL语句的准备状态,可以进行查询、删除等操作
        Prepare(query string) (Stmt, error)
        // 关闭当前的链接,执行释放连接拥有的资源等清理工作
        Close() error
        // 返回一个代表事务处理,通过它可以进行查询、更新等操作,或者对事务进行回滚、递交
        Begin() (Tx, error)
    }
    

CRUD

  1. 基本用法

    // 操作数据库
    db.AutoMigrate(&Product)
    db.Migrator().CreateTable(&Product)
    // https://gorm.io/docs/migration.html
    //版本管理- https://github. com/go-gormigrate/gormigrate
    user := User{ Name: "Jinzhu", Age: 18,Birthday: time.Now(O)}
    result := db.Create(&user) // pass pointer of data to Create
    user.ID         //返回主键 last insert id
    result.Error    //返回 error
    result.RowsAffected  //返回影响的行数var users []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, { Name:"jinzhu3"}}
    db.Create(&users)
    db.CreateInBatches(users,100)
    
  2. 基础概念

    • 优点: gorm 可以连接多种数据库,只需要不同的驱动即可。官方目前仅支持 MySQL、PostgreSQL、SQlite、SQL Server 四种数据库,可以通过自定义的方式接入其他数据库。

    • 连接代码

      // MySQL 配置信息
      username := "root"              // 账号
      password := "xxxxxx" // 密码
      host := "127.0.0.2"             // 地址
      port := 3306                    // 端口
      DBname := "test"               // 数据库名称
      timeout := "10s"                // 连接超时,10秒
      dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
      // Open 连接
      db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
      if err != nil {
          panic("failed to connect mysql.")
      }
      
    • 声明模型:

      // 数据库代码
      CREATE TABLE `gorm1`.`无标题`  (
        `id` int(0) NOT NULL AUTO_INCREMENT,
        `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
        `price` decimal(10, 2) NULL DEFAULT NULL,
        PRIMARY KEY (`id`) USING BTREE
      ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = CREATE TABLE `gorm1`.`无标题`  (
        `id` int(0) NOT NULL AUTO_INCREMENT,
        `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
        `price` decimal(10, 2) NULL DEFAULT NULL,
        PRIMARY KEY (`id`) USING BTREE
      ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
      ​
      // 对应的结构体
      type Goods struct {
          // gorm.Model  // 见下面的约定
          Id    int
          Name  string
          Price int
      }
      
    • 约定:

      1. gorm 制定了很多约定,并按照约定大于配置的思想工作, 比如会根据结构体的复数寻找表名,会使用 ID 作为主键,会根据 CreateAt、UpdateAt 和 DeletedAt 表示创建时间、更新时间和删除时间。

      2. gorm 提供了一个 Model 结构体,可以将它嵌入到自己的结构体中

        // 可实现软删除
        type Model struct {
          ID        uint           `gorm:"primaryKey"`
          CreatedAt time.Time
          UpdatedAt time.Time
          DeletedAt gorm.DeletedAt `gorm:"index"`
        }
        
      3. 字段标签 tag

        // 设置 tag 来对该字段一些属性进行定义
        type Post struct {
            Title string `gorm:"column:t, size:256, unique:true"`
            // 映射为 t,设置最大长度为 256,该字段唯一
        }
        
  3. 自动迁移

    在数据库的表尚未初始化时,gorm 可以根据指定的结构体自动建表。

    • 自动创建表

      type User struct {
          gorm.Model
          UserName string
          Password string
      }
      db.AutoMigrate(&User{})
      
  4. 创建数据

    user := User{UserName: "123", Password: "haha"}
    result := db.Create(&user)
    // 插入后返回常用的插入数据,用user. 调用 , 如 user.ID
    ​
    // 通过 Select 选择指定字段, 只插入指定字段
    result := db.Select("UserName").Create(&user)
    // 使用 Omit 方法过滤一些字段。
    result := db.Omit("UserName").Create(&user)
    ​
    // 批量插入
    users := []User{
        {UserName: "123", Password: "aaa"},
        {UserName: "234", Password: "bbb"},
        {UserName: "345", Password: "ccc"},
    }
    db.Create(&users)
    
  5. 查询数据

    • 查询单个数据: gorm 提供了 First、Take、Last 方法。它们都是通过 LIMIT 1 来实现的,分别是主键升序、不排序和主键降序。

      user := User{}
      // 获取第一条记录(主键升序)
      db.First(&user)
      // SELECT * FROM users ORDER BY id LIMIT 1;
      // 如果没有查询到对象,会返回 ErrRecordNotFound 错误。
      
    • 根据主键查询:

      db.First(&user, 2001)  // 也可以用 "2001"
      
    • 查询多个引用

      users := []User{}
      result := db.Find(&users)
      // 可以通过访问返回值上的 Error 和 RowsAffected 字段获取异常和影响的行号
      
    • where 条件

      db.Where("name <> ?", "wangming").Find(&users)
      

      传递 Struct、Map 和 切片时,可以实现更简便的设置条件

      db.Where(map[string]interface{}{"user_name": "wang", "password": "123"}).Find(&user)
      
    • 其他操作

      // 排序 Order  Order("no desc, password")
      // 分组 Group Having
      // Save 方法更新所有字段,即使是零值也会更新   db.Save(&user)
      // 使用 Model 和 Update 方法更新单列  db.Model(&user).Update("user_name", "haha")
      // 删除   db.Where().Delete(&user)   db.Delete(&User{}, 20) 根据主键删除
      // 特殊用法  db.Model(&User{Id: 111})..Update("age", gorm.Expr("age * ? + ?", 2, 100))
      ​