02 Go语言操作MySQL基础教程_20240729 课程笔记

概述

如果您没有Golang的基础,应该学习如下前置课程。

  • Golang零基础入门
  • Golang面向对象编程
  • Go Web 基础
  • Go语言开发REST API接口_20240728

基础不好的同学每节课的代码最好配合视频进行阅读和学习,如果基础比较扎实,则阅读本教程巩固一下相关知识点即可,遇到不会的知识点再看视频。

视频课程

最近发现越来越多的公司在用Golang了,所以精心整理了一套视频教程给大家,这个是其中的第5部,后续还会有很多。

视频已经录制完成,完整目录截图如下:
在这里插入图片描述

打个小广告,目前处于特价阶段,一节课只需要1块钱,29节课只需要29元哦。如果有需要,请前往我的淘宝店铺“Python私教”下单。

课程目录

  • 01 使用Go语言连接MySQL
  • 02 ySQL官方库的拉取和使用
  • 03 打开和关闭连接
  • 04 创建用户表
  • 05 新增用户
  • 06 根据ID查询用户
  • 07 查询所有的用户
  • 08 根据ID修改用户
  • 09 根据ID删除用户
  • 10 使用预处理查询所有的用户
  • 11 使用预处理新增用户
  • 12 事务的介绍和使用
  • 13 回顾RESTAPI接口开发
  • 14 开发获取所有用户信息的接口
  • 15 使用HTTP客户端测试获取所有用户接口
  • 16 开发和测试根据ID获取用户的接口
  • 17 开发和测试新增用户的接口
  • 18 开发和测试根据ID修改用户的接口
  • 19 开发根据ID删除用户的接口
  • 20 新增数据的SQL代码分析
  • 21 实现MySQL通用新增数据的方法
  • 22 测试MySQL通用新增数据的方法
  • 23 封装并测试通用的修改数据的方法
  • 24 封装并测试通用的删除方法
  • 25 封装通用的查询所有数据的方法
  • 26 将查询的数据转换为字典
  • 27 优化查询所有用户的方法
  • 28 实现根据ID查询并进行测试
  • 29 总结

精品代码

完整代码实在是太多了,放弃了给大家分享完整代码的想法,这里摘录一些个人认为比较精品的代码。

封装将SQL查询结果转换为字典的方法

这个方法想了很久,也查阅了大量的资料,最终被实现了。

代码封装如下:

package zdpgo_mcrud

import (
	"database/sql"
	"errors"
	"fmt"
	"strings"
)

func GetBy(
	db *sql.DB,
	tableName string,
	columns []string,
	conditions map[string]interface{},
) (data []map[string]interface{}, err error) {
	if db == nil {
		err = errors.New("db is nil")
		return
	}
	if tableName == "" {
		err = errors.New("tableName is empty")
		return
	}

	var columnStr string
	if columns == nil || len(columns) == 0 {
		columnStr = "*"
	} else {
		columnStr = strings.Join(columns, ",")
	}
	sqlStr := fmt.Sprintf(
		"select %s from %s",
		columnStr,
		tableName,
	)

	// 构造查询条件
	whereValues := []interface{}{}
	whereKeys := []string{}
	if conditions != nil && len(conditions) > 0 {
		// select * from user
		// select * from user where k=v
		for k, v := range conditions {
			whereKeys = append(whereKeys, fmt.Sprintf("%s=?", k))
			whereValues = append(whereValues, v)
		}
		whereStr := strings.Join(whereKeys, ",")
		sqlStr += " where " + whereStr
	}

	// 准备执行查询
	var stmt *sql.Stmt
	stmt, err = db.Prepare(sqlStr)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer stmt.Close()

	// 执行查询
	var rows *sql.Rows
	rows, err = stmt.Query(whereValues...)
	defer rows.Close()
	if rows == nil {
		err = errors.New("rows is nil")
		return
	}

	count := len(columns)                   // 列的个数
	values := make([]interface{}, count)    // 一组数据的值
	valuePtrs := make([]interface{}, count) // 一组数据的值的对应地址
	for rows.Next() {
		for i := 0; i < count; i++ {
			valuePtrs[i] = &values[i] // 将列的数据的值的地址取出来,赋值给地址值
		}
		err = rows.Scan(valuePtrs...) // 获取各列的值,放在对应地址中
		if err != nil {
			return
		}
		item := make(map[string]interface{}) // 构建列名和值的对应关系 {name:张三,age:22}
		for i, col := range columns {
			var v interface{}     // 临时值
			val := values[i]      // 对应的值
			b, ok := val.([]byte) // 判断能不能转换为字节数组,实际上就是判断是不是字符串
			if ok {
				v = string(b) // 转换为字符串
			} else {
				v = val
			}
			item[col] = v
		}
		data = append(data, item)
	}
	return
}

使用方法如下:

package main

import (
	"database/sql"
	"fmt"
	"github.com/zhangdapeng520/zdpgo_mcrud"
	_ "github.com/zhangdapeng520/zdpgo_mysql"
)

var (
	db  *sql.DB
	err error
)

func initMySQL() {
	dbUrl := "root:root@tcp(127.0.0.1:3306)/test"
	db, err = sql.Open("mysql", dbUrl)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func closeMySQL() {
	db.Close()
}

func main() {
	initMySQL()
	defer closeMySQL()
	err = db.Ping()
	if err != nil {
		fmt.Println(err)
		return
	}

	conditions := map[string]interface{}{
		"id": 1,
	}
	data, err := zdpgo_mcrud.GetBy(
		db,
		"user",
		[]string{"id", "name", "age"},
		conditions,
	)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(data)
}

有了这个方法以后,我们就有了一个通用的查询方法,不用再写重复的SQL语句了。

实现用户增删改查REST API接口

这个需要大家学习我之前的前置课,就是那个REST API的基础课。

再结合这个课程的MYSQL基础知识,就可以开发了。

服务端代码如下:

package main

import (
	"database/sql"
	"fmt"
	"github.com/zhangdapeng520/zdpgo_httprouter"
	_ "github.com/zhangdapeng520/zdpgo_mysql"
	"net/http"
	"time"
)

var (
	db  *sql.DB
	err error
)

func initMySQL() {
	dbUrl := "root:root@tcp(127.0.0.1:3306)/test"
	db, err = sql.Open("mysql", dbUrl)
	if err != nil {
		fmt.Println(err)
		return
	}
}

func closeMySQL() {
	db.Close()
}

type User struct {
	Id   int64  `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func DbGetAllUser() []User {
	var users []User

	sqlStr := "select id,name,age from user"

	var stmt *sql.Stmt
	stmt, err = db.Prepare(sqlStr)
	if err != nil {
		fmt.Println(err)
		return users
	}
	defer stmt.Close()

	var rows *sql.Rows
	rows, err = stmt.Query()
	defer rows.Close()

	// 读取
	for rows.Next() {
		var (
			uid  int64
			name string
			age  int
		)
		err = rows.Scan(&uid, &name, &age)
		if err != nil {
			fmt.Println(err)
			return users
		}
		users = append(users, User{uid, name, age})
		fmt.Println(uid, name, age)
	}

	return users
}
func DbGetUser(uid string) []User {
	var users []User

	sqlStr := "select id,name,age from user where id=?"

	var stmt *sql.Stmt
	stmt, err = db.Prepare(sqlStr)
	if err != nil {
		fmt.Println(err)
		return users
	}
	defer stmt.Close()

	var rows *sql.Rows
	rows, err = stmt.Query(uid)
	defer rows.Close()

	// 读取
	for rows.Next() {
		var (
			uid  int64
			name string
			age  int
		)
		err = rows.Scan(&uid, &name, &age)
		if err != nil {
			fmt.Println(err)
			return users
		}
		users = append(users, User{uid, name, age})
		fmt.Println(uid, name, age)
	}

	return users
}

func DbAddUser(name string, age int) int64 {
	sqlStr := "insert into user(name,age) values (?,?)"

	var stmt *sql.Stmt
	stmt, err = db.Prepare(sqlStr)
	if err != nil {
		fmt.Println(err)
		return -1
	}
	defer stmt.Close()

	var result sql.Result
	result, err = stmt.Exec(name, age)
	if err != nil {
		fmt.Println(err)
		return -1
	}

	var uid int64
	uid, err = result.LastInsertId()
	if err != nil {
		fmt.Println(err)
		return -1
	}

	fmt.Println("插入成功,ID是:", uid)
	return uid
}

func DbUpdateUser(name string, age int, id string) int64 {
	sqlStr := "update user set name=?, age=? where id=?"
	var result sql.Result
	result, err = db.Exec(sqlStr, name, age, id)
	if err != nil {
		fmt.Println(err)
		return 0
	}

	var rowNum int64
	rowNum, err = result.RowsAffected()
	if err != nil {
		fmt.Println(err)
		return 0
	}

	fmt.Printf("更新 %d 条数据成功\n", rowNum)
	return rowNum
}

func DbDeleteUser(id string) int64 {
	sqlStr := "delete from user where id=?"
	var result sql.Result
	result, err = db.Exec(sqlStr, id)
	if err != nil {
		fmt.Println(err)
		return 0
	}

	var rowNum int64
	rowNum, err = result.RowsAffected()
	if err != nil {
		fmt.Println(err)
		return 0
	}

	fmt.Printf("删除 %d 条数据成功\n", rowNum)
	return rowNum
}

func RouterGetAllUser(w http.ResponseWriter, r *http.Request, _ zdpgo_httprouter.Params) {
	users := DbGetAllUser()
	zdpgo_httprouter.ResponseSuccess(w, &users)
}

func RouterGetUser(w http.ResponseWriter, r *http.Request, ps zdpgo_httprouter.Params) {
	uid := ps.ByName("id")
	users := DbGetUser(uid)
	var user User
	if len(users) > 0 {
		user = users[0]
	}
	zdpgo_httprouter.ResponseSuccess(w, &user)
}

func RouterAddUser(w http.ResponseWriter, r *http.Request, _ zdpgo_httprouter.Params) {
	var user User
	zdpgo_httprouter.GetJson(r, &user)
	uid := DbAddUser(user.Name, user.Age)
	user.Id = uid
	zdpgo_httprouter.ResponseSuccess(w, &user)
}
func RouterUpdateUser(w http.ResponseWriter, r *http.Request, ps zdpgo_httprouter.Params) {
	var user User
	zdpgo_httprouter.GetJson(r, &user)
	uid := ps.ByName("id")
	updateRows := DbUpdateUser(user.Name, user.Age, uid)
	zdpgo_httprouter.ResponseSuccess(w, updateRows)
}
func RouterDeleteUser(w http.ResponseWriter, r *http.Request, ps zdpgo_httprouter.Params) {
	uid := ps.ByName("id")
	updateRows := DbDeleteUser(uid)
	zdpgo_httprouter.ResponseSuccess(w, updateRows)
}

func main() {
	initMySQL()
	defer closeMySQL()
	err = db.Ping()
	if err != nil {
		fmt.Println(err)
		return
	}

	router := zdpgo_httprouter.New()
	router.GET("/user", RouterGetAllUser)
	router.GET("/user/:id", RouterGetUser)
	router.POST("/user", RouterAddUser)
	router.PUT("/user/:id", RouterUpdateUser)
	router.DELETE("/user/:id", RouterDeleteUser)

	server := &http.Server{
		Addr:         "0.0.0.0:8888",
		Handler:      router,
		ReadTimeout:  5 * time.Second,
		WriteTimeout: 5 * time.Second,
	}

	server.ListenAndServe()
}

客户端代码也有增删改查的,这里以根据ID删除为例子。

package main

import (
	"fmt"
	"github.com/zhangdapeng520/zdpgo_httprouter"
	"io"
)

func main() {
	targetUrl := "http://localhost:8888/user/3"
	data := map[string]interface{}{}
	resp, err := zdpgo_httprouter.SendJson("DELETE", targetUrl, data)
	if err != nil {
		fmt.Println(err)
		return
	}

	body := resp.Body
	bodyBytes, err := io.ReadAll(body)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(bodyBytes))
}

总结

本套教程主要讲解Go语言操作MySQL的基础知识,同时还讲解了如何结合之前学习的REST API的基础知识,开发用户增删改查的API接口,最后还通过对MySQL通用方法的封装,让大家学习到MySQL的进阶使用技巧。

如果您需要完整的源码,打赏20元即可。

人生苦短,我用Python,我是您身边的Python私教~

  • 43
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Python私教

创业不易,请打赏支持我一点吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值