首页 > 数据库 >02 Go语言操作MySQL基础教程_20240729 课程笔记

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

时间:2024-08-02 21:52:44浏览次数:12  
标签:02 return nil err fmt 20240729 user 基础教程 Println

概述

如果您没有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私教~

标签:02,return,nil,err,fmt,20240729,user,基础教程,Println
From: https://blog.csdn.net/qq_37703224/article/details/140782954

相关文章

  • 2024.8 做题记录 /
    galaxyplan8.2A.小怪兽(monster)你说得对但是决策单调性状物代价相等的都包含进去分治可以ac,正确性不知道,至少复杂度是假的。不过下述做法考场也想到了。首先做一个比较小的转化,\(Ans=n-\frac{1}{n}\sum_i\sum_j[a_i\leqp_j]\),这样就不用管一些乱七八糟的东西了谢谢喵>w<......
  • 1990-2022年 上市公司-战略差异度(原始数据、计算代码、参考文献和最终计算结果)
    上市公司战略差异度是衡量企业在战略制定和实施过程中所展现的独特性和创新性的指标。它体现了公司对市场环境、行业趋势及自身能力的独特见解和战略布局。通过分析上市公司的战略差异度,可以深入理解企业的市场竞争策略、行业定位和发展方向。战略差异度的重要性市场竞争力:战......
  • 2000-2022年 上市公司-投融资期限错配、短债长用、短贷长投(原始数据、计算代码、参考
    上市公司在投融资过程中的管理决策对企业的财务稳定性和长期发展至关重要。投融资期限错配、短债长用和短贷长投是企业在资本运作中可能出现的问题,它们影响着企业的财务结构和风险管理。投融资问题概述投融资期限错配指企业资产与债务的期限不匹配,通常表现为资金来源短期化......
  • 上海计算机学会2022年5月月赛C++乙组T3狼人游戏(二)
    狼人游戏(二)内存限制: 256 Mb时间限制: 1000 ms题目描述有 n 名玩家在玩狼人游戏,有一些玩家的身份是狼人。其余玩家的身份是预言家。游戏的进程中,陆续出现了 m 句发言,每句发言来自于某个玩家,发言的信息是声称另一个玩家的身份是狼人或者是预言家。小爱猜想,狼人的发......
  • 2024“钉耙编程”中国大学生算法设计超级联赛(5)
    Preface唉感觉最近把把红温负作用啊,这场就中期写05被卡常了就红温了一整场,放着更简单的题不写就疯狂乱搞结果不出所料地被打爆了,只能说是好似,赛后发现甚至有个题是去年一轮的原,结果比赛的时候没一个人看题意,属实绷不住了感觉现在每场的策略和心态都有很大问题啊,不把这些问题......
  • 2024-8-2 信友队模考总结
    开考没有一道题一眼,感觉要没,不好搞。开考就一直看T1,想出来20pts暴力解法,之后就一直停滞不前,尤其是T3直接蒙了。想了一个多小时还没开始写,感觉真的没了。开写T1暴力先放放,去搞T2,很快写出来但是被自己证伪了,于是去看T3。想出来一个完完全全的大搜索但是感觉连部分分都拿......
  • 2024.8.2 test
    A有长度为\(n\)序列\(A\),你要把构造长度相同的序列\(B\)使得\(\sumB_i=m\)。满足随机打乱\(B_i\)后,期望\(\sum[A_i>B_i]\)最小,求这个值。\(n\le1000,m\le5000\)。我们考虑背包,也就是\(0\simm\)的数选\(n\)个出来,和为\(m\)。设\(sum_i\)表示\(A_i\)里......
  • ISC.AI 2024人工智能峰会——个人笔记
    个人记录篇360开放明星场景,邀请国内最强大模型合作名单:零一万物,华为云,科大讯飞,百度,火山引擎,商汤,360,智谱AI,百川智能,腾讯,MiniMax,面壁智能,阿里云,DeepSeek,学而思(九章大模型)。网络安全专项扶持政策上海市普陀区:详情见视频回放“ISC.AI2024上海AI峰会”的28分42秒至47分整。......
  • C高级(学习)2024.8.2
    目录1.指针函数概念格式2.函数指针概念格式基本用法3.函数指针数组概念格式  4.共用体格式定义共用体变量特性5.枚举定义格式6.存储类型(1)auto(2)static(3)extern(4)register7.条件编译(1)根据宏是否定义(2)根据宏值(3)防止头文件重复包含(放在头文件中)1.指针函......
  • 2024中国天气网 实况天气API JSON格式接口
    中国天气网API接口GBK格式json数据:http://www.weather.com.cn/data/sk/101010100.htmlhttp://www.weather.com.cn/data/cityinfo/101010100.html{“weatherinfo”:{“city”:“鍖椾含”,“cityid”:“101010100”,“temp”:“18”,“WD”:“涓滃崡椋�”,“WS”:“1绾�”,......