快速上手用Go操作MySQL

146 阅读6分钟

获取数据库驱动

-->> 驱动github地址<<--

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

如果你遇到下面的错误,

image.png

键入这行命令即可(亲测有效)

go env -w GO111MODULE=auto

GO111MODULE 是一个控制 Go 模块机制行为的环境变量。当 GO111MODULE 的值为 auto 时,Go 命令会自动判断是否在模块模式下运行。如果当前目录下存在一个 go.mod 文件,则认为在模块模式下运行;否则认为在传统的 GOPATH 模式下运行。

在模块模式下,Go 会自动下载并管理依赖项,并且可以使用更加灵活的版本控制方式。而在 GOPATH 模式下,则需要手动下载并管理依赖项,并且版本控制方式相对固定。

如果不想手动设置 GO111MODULE 环境变量,并希望让 Go 命令自动判断模式,可以使用 go env -w GO111MODULE=auto 命令来设置。这个命令会将 GO111MODULE 环境变量设置为 auto,从而让 Go 命令自动判断模式。

连接初始化

package main


import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql" // 匿名导入 自动执行 init()
	"net/url"
	"time"
)

// 声明一个db
var db *sql.DB

func initMysql() (err error) {
   // 东八区,允许解析时间字段
   // 如果你有datetime 类型的字段,方便后面解析
   // 后面的 parseTime 必须要有,用法如下:
   dsn := "root:123456@tcp(127.0.0.1:3306)/你的库名?charset=utf8&loc=" + url.QueryEscape("Asia/Shanghai") + "&parseTime=true"
   // 只对格式进行校验,并不会真正连接数据库
   db, err = sql.Open("mysql", dsn) 
   if err != nil {
      return err
   }

   // Ping 验证与数据库的连接是否仍处于活动状态,并在必要时建立连接。
   err = db.Ping()
   if err != nil {
      fmt.Printf("connect to db failed, err: %v\n", err)
      return err
   }
   // 数值需要根据业务具体情况来确定
   // 设置可以重用连接的最长时间
   db.SetConnMaxLifetime(time.Second * 60)
   // 设置连接可能处于空闲状态的最长时间
   db.SetConnMaxIdleTime(time.Second * 30)
   // 设置与数据库的最大打开连接数
   db.SetMaxOpenConns(200)
   //  设置空闲连接池中的最大连接数
   db.SetMaxIdleConns(10) 
   return nil
}

func main() {
	if err := initMysql(); err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
	}
	// 检查完错误之后执行,确保 db 不为 nil
	// Close() 用来释放数据库连接相关的资源
	defer func(db *sql.DB) {
		err := db.Close()
		if err != nil {
			panic(err)

		}
	}(db)

	fmt.Println(">>>>>>数据库格式正确,接着往下走")


}

运行结果

image.png

CURD

查询数据

// 定义一个结构体,首先你得去数据创建这张Team表
type Team struct {
	TeamId       int
	TeamName     string
	TeamDesc     string
	CreateTime   time.Time

}
// 查询单行数据
func queryDemo(id int) (Team, error) {
	sqlStr := "select teamId, teamName, teamDesc from team where teamId = ? "

	var team Team
	// QueryRow 执行预期最多返回一行的查询。
	// QueryRow 始终返回一个非 nil 值。错误将延迟到调用 row 的 Scan 方法。
	// Scan 将匹配行中的列复制到 dest 指向的值中
	// 如果多行与查询匹配,Scan 将使用第一行并丢弃其余行。
	// 如果没有与查询匹配的行,Scan 将返回 ErrNoRows。
	// QueryRow 之后要调用 Scan 方法,否则数据库连接不会被释放
	// Scan 源码:defer r.rows.Close()
	err := db.QueryRow(sqlStr, id).Scan(&team.TeamId, &team.TeamName, &team.TeamDesc)
	if err != nil {
		fmt.Printf("scan failed ,err: ->%v\n", err)
		return team, err
	}
	return team, nil

}


func main() {
	if err := initMysql(); err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
	}
	// 检查完错误之后执行,确保 db 不为 nil
	// Close() 用来释放数据库连接相关的资源
	defer func(db *sql.DB) {
		err := db.Close()
		if err != nil {
			panic(err)

		}
	}(db)

	fmt.Println(">>>>>>数据库格式正确,接着往下走")
	fmt.Println("===========================")

	//>>>>>>>>>>>>> 查单行
	team, err := queryDemo(33)
	if err != nil {
		fmt.Printf("query row failed, err: %v", err)
	}
	fmt.Printf("id: %d name: %s desc: %s\n", team.TeamId, team.TeamName, team.TeamDesc)


}

结果

image.png

// 查询多条数据
func queryMultiRowDemo(id int) {
	sqlStr := "select teamId, teamName, teamDesc , createTime from team where teamId > ? "

	rows, err := db.Query(sqlStr, id)
	if err != nil {
		fmt.Printf("query failed, err: %v\n", err)
		return
	}
	// 关闭 rows 释放持有的数据库链接
	// Close 关闭行,防止进一步枚举。
	// 如果调用 Next 并返回 false 并且没有其他结果集,
	// 则行将自动关闭,检查 Err. 的结果就足够了。 关闭是幂等的,不会影响 Err 的结果。
	// 因为不能保证 for rows.Next() 一定可以执行完,有可能会 panic 或其他情况,
	// 故需要在此 defer 关闭连接
	defer rows.Close()

	// 循环读取结果集中的数据
	// Next 准备下一个结果行,以便使用 Scan 方法读取。
	// 成功时返回 true,如果没有下一个结果行或在准备时发生错误,则返回 false。
	for rows.Next() {
		var team Team

		err := rows.Scan(&team.TeamId, &team.TeamName, &team.TeamDesc, &team.CreateTime)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}

		// 将Time类型的时间格式化成`int64`类型(timestamp)
		//createtime := team.CreateTime.Unix()

		// 将Time类型的时间格式化成`string`类型(Y-m-d H:i:s)
		/*
			一个格式化字符串 "2006-01-02 15:04:05"。

			这个格式化字符串是一个特殊的字符串,它是 Go 语言中时间格式化的标准格式,其中每个数字和字母都有特定的含义,用于表示时间的不同部分,例如年份、月份、日期、小时、分钟和秒钟等。

			在这个例子中,格式化字符串 "2006-01-02 15:04:05" 表示时间的格式为 "年-月-日 时:分:秒",其中 "2006" 表示年份,"01" 表示月份,"02" 表示日期,"15" 表示小时(24 小时制),"04" 表示分钟,"05" 表示秒钟。
		*/
		createtime2 := team.CreateTime.Format("2006-01-02 15:04:05")
		fmt.Printf("id: %d name: %s desc: %s  createTime: %s\n", team.TeamId, team.TeamName, team.TeamDesc, createtime2)

	}
}

func main() {
	if err := initMysql(); err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
	}
	// 检查完错误之后执行,确保 db 不为 nil
	// Close() 用来释放数据库连接相关的资源
	defer func(db *sql.DB) {
		err := db.Close()
		if err != nil {
			panic(err)

		}
	}(db)

	fmt.Println(">>>>>>数据库格式正确,接着往下走")
	fmt.Println("===========================")

	// >>>>>>>>>>查单行
	team, err := queryDemo(33)
	if err != nil {
		fmt.Printf("query row failed, err: %v", err)
	}
	fmt.Printf("id: %d name: %s desc: %s\n", team.TeamId, team.TeamName, team.TeamDesc)
	fmt.Println("===========================")
	// >>>>>>>>>>查多行
	queryMultiRowDemo(20)
  fmt.Println("===========================")
        .
        .
        .
        .


}

结果

image.png

插入数据

// 插入数据
func insertRowDemo(team Team) (int64, error) {
	sqlStr := "insert into team " +
		"(teamId, teamName, teamDesc)" +
		"values (?,?,?);"
	result, err := db.Exec(sqlStr, &team.TeamId, &team.TeamName, &team.TeamDesc)
	if err != nil {
		fmt.Printf("insert failed, err: %v\n", err)
		return 0, err
	}
	// LastInsertId 返回数据库为响应命令而生成的整数。
	// 通常,这将来自插入新行时的“自动增量”列。
	// 并非所有数据库都支持此功能,并且此类语句的语法各不相同。
	var newID int64
	newID, err = result.LastInsertId() // 新插入数据的id
	//affected, err := result.RowsAffected() // 影响的行数
	if err != nil {
		fmt.Printf("get lastinsert ID failed, err: %v\n", err)
		return 0, err
	}
	return newID, nil
}

更新数据

// 更新数据
func updateRowDemo(team *Team) (int64, error) {
	sqlStr := "UPDATE team SET teamName=? WHERE teamId = ?"
	ret, err := db.Exec(sqlStr, &team.TeamName, &team.TeamId)
	if err != nil {
		fmt.Printf("update failed, err: %v\n", err)
		return 0, err
	}
	// 返回受更新、插入或删除影响的行数。并非每个数据库或数据库驱动程序都支持此功能。
	var n int64
	n, err = ret.RowsAffected() // 操作影响的行数
	if err != nil {
		fmt.Printf("get RowsAffected failed, err: %v\n", err)
		return 0, err
	}
	return n, nil
}

删除数据

// 删除数据
func deleteRowDemo(id int) (int64, error) {
	sqlStr := "DELETE FROM team WHERE teamId = ?"
	ret, err := db.Exec(sqlStr, id)
	if err != nil {
		fmt.Printf("delete failed, err: %v\n", err)
		return 0, err
	}
	// RowsAffected returns the number of rows affected by an
	// update, insert, or delete. Not every database or database
	// driver may support this.
	var n int64
	n, err = ret.RowsAffected() // 操作影响的行数
	if err != nil {
		fmt.Printf("get RowsAffected failed, err: %v\n", err)
		return 0, err
	}
	return n, nil
}