操作MySQL数据库(增删改查代码演示)

package main

import (
   "database/sql"
   "fmt"
   _ "github.com/go-sql-driver/mysql"
   "strings"
)

func main() {
   // 构造DSN字符串,格式  账号:密码@tcp(主机地址:端口号)/数据库名?charset=字符编码
   dataSourceName := "username:password@tcp(localhost:3306)/database?charset=utf8mb4"

   db, err := sql.Open("mysql", dataSourceName)
   if err != nil {
      panic(err.Error())
   }

   // 关闭数据库
   defer func(db *sql.DB) {
      _ = db.Close()
   }(db)

   // 检查连接数据库是否成功
   err = db.Ping()
   if err != nil {
      panic(err.Error())
   }

   //========== 查询单条记录(指定字段) ==========//

   // 构造SQL语句
   var query strings.Builder
   query.WriteString("SELECT ")
   query.WriteString("    `id`, ")
   query.WriteString("    `title`, ")
   query.WriteString("    `click` ")
   query.WriteString("FROM ")
   query.WriteString("    `prefix_article` ")
   query.WriteString("WHERE ")
   query.WriteString("    `id` = ? ")
   id := 53

   // 创建变量用于保存字段值
   var fieldId int64
   var fieldTitle string
   var fieldClick int64

   // 执行SQL并把查询结果的字段值保存到对应的变量
   row := db.QueryRow(query.String(), id)
   err = row.Scan(&fieldId, &fieldTitle, &fieldClick)
   if err != nil {
      panic(err.Error())
   }

   fmt.Printf("第%v%v 【点击:%v\n", fieldId, fieldTitle, fieldClick)

   //========== 查询单条记录(所有字段) ==========//

   // 构造SQL语句
   query.Reset()
   query.WriteString("SELECT ")
   query.WriteString("    `*` ")
   query.WriteString("FROM ")
   query.WriteString("    `prefix_article` ")
   query.WriteString("WHERE ")
   query.WriteString("    `id` = ? ")
   id = 53

   // 执行SQL
   rows, err := db.Query(query.String(), id)
   if err != nil {
      panic(err.Error())
   }

   // 关闭结果集
   defer func(rows *sql.Rows) {
      _ = rows.Close()
   }(rows)

   // 获取所有字段名
   columns, err := rows.Columns()
   if err != nil {
      panic(err.Error())
   }

   values := make([][]byte, len(columns)) // 用于保存字段值
   dest := make([]any, len(columns))
   for i := range values {
      dest[i] = &values[i]
   }

   // 遍历结果集
   for rows.Next() {
      err = rows.Scan(dest...)
      if err != nil {
         panic(err.Error())
      }
   }

   record := map[string]string{} // 用于保存记录(单条)
   for i := range values {
      record[columns[i]] = string(values[i])
   }

   fmt.Printf("第%v%v 【点击:%v\n", record["id"], record["title"], record["click"])

   //========== 查询多条记录(所有字段) ==========//

   page := 2     // 页码
   pageSize := 5 // 每页显示记录数

   // 构造SQL语句
   query.Reset()
   query.WriteString("SELECT ")
   query.WriteString("    `*` ")
   query.WriteString("FROM ")
   query.WriteString("    `prefix_article` ")
   query.WriteString("ORDER BY ")
   query.WriteString("    `id` DESC ")
   query.WriteString("LIMIT ?, ? ")

   // 执行SQL
   rows, err = db.Query(query.String(), (page-1)*pageSize, pageSize)
   if err != nil {
      panic(err.Error())
   }

   // 关闭结果集
   defer func(rows *sql.Rows) {
      _ = rows.Close()
   }(rows)

   // 获取所有字段名
   columns, err = rows.Columns()
   if err != nil {
      panic(err.Error())
   }

   values = make([][]byte, len(columns)) // 用于保存字段值
   dest = make([]any, len(columns))
   for i := range values {
      dest[i] = &values[i]
   }

   var records []map[string]string // 用于保存记录(多条)

   // 遍历结果集
   for rows.Next() {
      err = rows.Scan(dest...)
      if err != nil {
         panic(err.Error())
      }

      r := map[string]string{} // 单条记录的数据
      for j := range values {
         r[columns[j]] = string(values[j])
      }

      records = append(records, r)
   }

   // 遍历所有记录
   for _, value := range records {
      fmt.Printf("第%v%v 【点击:%v\n", value["id"], value["title"], value["click"])
   }

   //========== 插入记录 ==========//

   // 构造SQL语句
   query.Reset()
   query.WriteString("INSERT INTO")
   query.WriteString("    `prefix_article` ")
   query.WriteString("SET")
   query.WriteString("    `title` = ?, ")
   query.WriteString("    `click` = ? ")
   title := "PHP是世界上最好の语言"
   click := 1024

   // 执行SQL
   exec, err := db.Exec(query.String(), title, click)
   if err != nil {
      panic(err.Error())
   }

   // 获取记录的自增主键ID(如果没有自增主键则为0)
   insertId, err := exec.LastInsertId()
   if err != nil {
      panic(err.Error())
   }
   fmt.Printf("insertId = %+v \n", insertId)

   //========== 更新记录 ==========//

   // 构造SQL语句
   query.Reset()
   query.WriteString("UPDATE ")
   query.WriteString("    `prefix_article` ")
   query.WriteString("SET")
   query.WriteString("    `click` = ? ")
   query.WriteString("WHERE ")
   query.WriteString("    `id` = ? ")
   click = 10086
   id = 10086

   // 执行SQL
   result, err := db.Exec(query.String(), click, id)
   if err != nil {
      panic(err.Error())
   }

   // 获取更新记录数
   affected, err := result.RowsAffected()
   if err != nil {
      panic(err.Error())
   }
   fmt.Printf("共更新%+v条记录\n", affected)

   //========== 删除记录 ==========//

   // 构造SQL语句
   query.Reset()
   query.WriteString("DELETE FROM")
   query.WriteString("    `prefix_article` ")
   query.WriteString("WHERE ")
   query.WriteString("    `id` = ? ")
   id = 10086

   // 执行SQL
   exec, err = db.Exec(query.String(), id)
   if err != nil {
      panic(err.Error())
   }

   rowsAffected, err := exec.RowsAffected()
   if err != nil {
      panic(err.Error())
   }
   fmt.Printf("共删除%+v条记录\n", rowsAffected)
}

//========== 总结 ==========//
// 1、sql.Open()只验证其参数是否正确,并不创建与数据库的连接,想检查与数据库是否连接成功可以使用db.Ping()。
// 2、DB可以安全地供多个协程并发使用,并维护自己的空闲连接池,故sql.Open()应该只调用一次,很少需要调用db.Close()关闭数据库。
// 3、如果查询结果集使用了“for rows.Next()”遍历,也可以不调用rows.Close()手动关闭结果集,因为遍历完后会自动关闭,并且自动
//    关闭后再调用rows.Close()手动关闭也不会报错,因为Close()方法是幂等的,不过为了安全起见和养成良好的编码习惯,最好还是手
//    动关闭结果集。

Copyright © 2024 码农人生. All Rights Reserved