【REST2SQL】07 GO 操作 Mysql 数据库
【REST2SQL】01RDB关系型数据库REST初设计
【REST2SQL】02 GO连接Oracle数据库
【REST2SQL】03 GO读取JSON文件
【REST2SQL】04 REST2SQL第一版Oracle版实现
【REST2SQL】05 GO 操作 达梦 数据库
【REST2SQL】06 GO 跨包接口重构代码
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle旗下产品。MySQL是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一。
MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型和大型网站的开发都选择 MySQL作为网站数据库。
1 准备工作
我的操作环境:
操作系统:Win10 x64
数据库: Ver 8.0.35 for Win64 on x86_64 (MySQL Community Server - GPL)
go:1.21.5
LiteIDE : X38.3
1.1 安装Mysql数据
登录 Mysql 官网,有Mysql社区版可以下载,官网下载显示的是32位,实际上安装包里也包括64位的,下载成功后,安装配置等这里省略5217字,我安装后就是64位的,自己脑补。
创建测试表 guci
导入部分测试数据
1.2 Mysql go驱动安装
第三方驱动下载。
go get -u github.com/go-sql-driver/mysql
//其中包含一个依赖库
go get -u filippo.io/edwards25519
众所周知的原因,可能同步失败,自己想办法翻墙或代理等一系列操作。
我这里偶尔能登录github.com网站,我从网站上手动下载下来加到开发环境中的src
2 新建一个gomysql的项目
新建一下gomysql的项目用来测试go操作mysql数据库。
2.1 go连接Mysql数据库
1 引入相关包
import ("database/sql""database/sql/driver"_ "github.com/go-sql-driver/mysql"
)
2 声明连接字符串
var ConnString string = "mysql://blma:5217@tcp(127.0.0.1:3306)/blma"
3 连接数据库
// 连接Mysql数据库
func connDB(connStr string) *sql.DB {end := strings.Index(connStr, "://")if end < 0 {log.Println("连接字符串设置有误。")panic(nil)}driverName := connStr[:end] // dmconnstring := connStr[end+3:]db, err := sql.Open(driverName, connstring)dieOnError("Can't open the driver:", err)if err = db.Ping(); err != nil {fmt.Println("不能连接mysql数据库:", err)return nil}// fmt.Printf("connect to \"%s\" succeed.\n", connStr)return db
}
2.2 实现CRUD
CUD比较简单,都执行execSQL操作,只是sql语句不同。
代码如下:
/* 往表插入数据 */
func insertData(insertSql string) string {result, _ := execSQL(insertSql)rows, err := result.RowsAffected()dieOnError("Can't insert", err)ret := map[string]int{"Insert rowsAffected": int(rows),}jsonBytes, err := json.Marshal(ret)dieOnError("map 转 json失败:", err)return string(jsonBytes)
}/* 删除表数据 */
func deleteData(deleteSql string) string {result, _ := execSQL(deleteSql)rows, err := result.RowsAffected()dieOnError("Can't delete", err)ret := map[string]int{"Delete rowsAffected": int(rows),}jsonBytes, err := json.Marshal(ret)dieOnError("map 转 json失败:", err)return string(jsonBytes)
}/* 修改表数据 */
func updateData(updateSql string) string {result, _ := execSQL(updateSql)rows, err := result.RowsAffected()dieOnError("Can't update", err)ret := map[string]int{"Update rowsAffected": int(rows),}jsonBytes, err := json.Marshal(ret)dieOnError("map 转 json失败:", err)return string(jsonBytes)// var sql =// result, err := db.Exec(sql)// if err != nil {// return err// }// affectedRows, _ := result.RowsAffected()// fmt.Println("updateTable succeed Affected rows:", affectedRows)// return nil
}// 执行SQL, execute stmt (INSERT, UPDATE, DELETE, DML, PLSQL) and return driver.Result object
func execSQL(sqls string) (result driver.Result, err error) {//连接数据库DB := connDB(ConnString)//延迟关闭连接defer DB.Close()statement, err := DB.Prepare(sqls)if err != nil {fmt.Println("prepare statement failed:", err.Error())}defer statement.Close()//执行SQL, execute stmt (INSERT, UPDATE, DELETE, DML) and return driver.Result objectresult, err = statement.Exec()if err != nil {fmt.Println("Exec failed:", err.Error())}dieOnError("Can't execSql() ", err)return result, err
}
2.3 动态查询有点费劲
没仔细研究Mysql的驱动,还是用达梦数据库的思路。
总体思路是先查询获取 *sql.Rows对象,从这里通过rows.Columns()和 rows. ColumnTypes()再获取列名切片和列类型信息,第三步把列名和数据库数据类型组合在一个map[string]string里;第四步初始化列值接收变量;第五步 rows.Next() 逐行遍历返回结果集并根据数据库类型(目前只匹配的VARCHER2 和 NUMBER,遇到其它类型再匹配)转换为Go的数据类型,组成一个dataset数据集;第六步序列化并转json返回查询结果。
代码如下:
/* 查询表数据 */
func selectData(sqlSelect string) string {// 连接数据库DB := connDB(ConnString)//延迟关闭连接defer DB.Close()// 准备查询语句statement, err := DB.Prepare(sqlSelect)if err != nil {fmt.Println("prepare statement failed:", err.Error())return ""}defer statement.Close()
// 1查询rows, err := statement.Query()if err != nil {fmt.Println("query failed:", err.Error())}// 2查询的列名称切片columns, err := rows.Columns()if err != nil {fmt.Println(err.Error())return ""}//fmt.Println(columns)// 3数据库列类型cType, err := rows.ColumnTypes()if err != nil {log.Fatal(err)}//fmt.Println(cType[0].Name(), cType[0].DatabaseTypeName())// 4列名类型mapcoltyp := colType(cType)// 5初始化列值接收变量row := make([]sql.RawBytes, len(columns))scanArgs := make([]interface{}, len(row))for i := range row {scanArgs[i] = &row[i]}// 查询结果数据集var dataset []map[string]interface{} //元素为map的切片for rows.Next() {err := rows.Scan(scanArgs...)if err != nil {panic(err.Error())}// rowvar row1 map[string]interface{} = make(map[string]interface{})for pos, col := range row {//fmt.Println(columns[pos], ":", string(col))colname := columns[pos]svalue := string(col)//数据类型处理value := typeConv(colname, svalue, coltyp)row1[colname] = value}//fmt.Println("row1:", row1)dataset = append(dataset, row1)//fmt.Println()}if err != io.EOF {dieOnError("Can't Next", err)}//切片转jsonjsonBytes, err := json.Marshal(dataset)dieOnError("slice 转 json失败:", err)//fmt.Println(string(jsonBytes))return string(jsonBytes)
}// 生成列名和类型 map
func colType(cType []*sql.ColumnType) map[string]string {var colTyp map[string]string = make(map[string]string)for _, col := range cType {colTyp[col.Name()] = col.DatabaseTypeName()}//fmt.Println(colTyp)return colTyp
}// 字符根据数据库类型转为go数据类型
func typeConv(colname string, svalue string, ct map[string]string) interface{} {var ret interface{}switch ct[colname] {case "VARCHAR":ret = svaluecase "DECIMAL":if len(svalue) > 0 {flt, err := strconv.ParseFloat(svalue, 64)if err != nil {fmt.Println("转换失败:", colname, svalue, err)} else {ret = flt}} else { //空串处理ret = nil}default:ret = svalue}return ret
}
3 全部代码及运行结果截图
全部代码:
/*该例程实现了Mysql数据库插入数据,修改数据,删除数据,数据查询等基本操作。*/
package main// 引入相关包
import ("database/sql""database/sql/driver""encoding/json""fmt""io""log""strconv""strings"_ "github.com/go-sql-driver/mysql"
)var ConnString string = "mysql://blma:5217@tcp(127.0.0.1:3306)/blma"// var ConnString string = config.Conf.ConnStringfunc main() {fmt.Println("\ngo 操作mysql数据库 demo")var (sqls string //sql语句result string //sql执行后返回的结果)//显示版本号showMysqlVersion()// // insert 插入一行数据sqls = `INSERT INTO kezz(p_id,s_dm,s_mc,n_zzxj) VALUES(-101,'125217','白龙马',5217);`result = insertData(sqls)fmt.Println(result)// update 更新数据sqls = "UPDATE kezz SET n_zzxj = 111 WHERE p_id = -100"result = updateData(sqls)fmt.Println(result)// delete 删除数据sqls = "delete from kezz where p_id = -109"result = deleteData(sqls)fmt.Println(result)// select 查询数据sqls = "select p_id,s_dm,s_mc,n_zzxj from kezz limit 5 "result = selectData(sqls)fmt.Println(result)}func showMysqlVersion() {//连接数据库db := connDB(ConnString)var version stringerr2 := db.QueryRow("SELECT VERSION()").Scan(&version)if err2 != nil {log.Fatal(err2)}fmt.Println("Mysql:", version)
}// 连接Mysql数据库
func connDB(connStr string) *sql.DB {end := strings.Index(connStr, "://")if end < 0 {log.Println("连接字符串设置有误。")panic(nil)}driverName := connStr[:end] // dmconnstring := connStr[end+3:]db, err := sql.Open(driverName, connstring)dieOnError("Can't open the driver:", err)if err = db.Ping(); err != nil {fmt.Println("不能连接mysql数据库:", err)return nil}// fmt.Printf("connect to \"%s\" succeed.\n", connStr)return db
}// 发生错误退出1
func dieOnError(msg string, err error) {if err != nil {log.Println(msg, err)//os.Exit(1)}
}/* 往表插入数据 */
func insertData(insertSql string) string {result, _ := execSQL(insertSql)rows, err := result.RowsAffected()dieOnError("Can't insert", err)ret := map[string]int{"Insert rowsAffected": int(rows),}jsonBytes, err := json.Marshal(ret)dieOnError("map 转 json失败:", err)return string(jsonBytes)
}/* 删除表数据 */
func deleteData(deleteSql string) string {result, _ := execSQL(deleteSql)rows, err := result.RowsAffected()dieOnError("Can't delete", err)ret := map[string]int{"Delete rowsAffected": int(rows),}jsonBytes, err := json.Marshal(ret)dieOnError("map 转 json失败:", err)return string(jsonBytes)
}/* 修改表数据 */
func updateData(updateSql string) string {result, _ := execSQL(updateSql)rows, err := result.RowsAffected()dieOnError("Can't update", err)ret := map[string]int{"Update rowsAffected": int(rows),}jsonBytes, err := json.Marshal(ret)dieOnError("map 转 json失败:", err)return string(jsonBytes)
}// 执行SQL, execute stmt (INSERT, UPDATE, DELETE, DML, PLSQL) and return driver.Result object
func execSQL(sqls string) (result driver.Result, err error) {//连接数据库db := connDB(ConnString)//延迟关闭连接defer db.Close()statement, err := db.Prepare(sqls)if err != nil {fmt.Println("prepare statement failed:", err.Error())}defer statement.Close()//执行SQL, execute stmt (INSERT, UPDATE, DELETE, DML) and return driver.Result objectresult, err = statement.Exec()if err != nil {fmt.Println("Exec failed:", err.Error())}dieOnError("Can't execSql() ", err)return result, err
}/* 查询表数据 */
func selectData(sqlSelect string) string {// 连接数据库db := connDB(ConnString)//延迟关闭连接defer db.Close()// 准备查询语句statement, err := db.Prepare(sqlSelect)if err != nil {fmt.Println("prepare statement failed:", err.Error())return ""}defer statement.Close()// 1查询rows, err := statement.Query()if err != nil {fmt.Println("query failed:", err.Error())}// 2查询的列名称切片columns, err := rows.Columns()if err != nil {fmt.Println(err.Error())return ""}//fmt.Println(columns)// 3数据库列类型cType, err := rows.ColumnTypes()if err != nil {log.Fatal(err)}//fmt.Println(cType[0].Name(), cType[0].DatabaseTypeName())// 4列名类型mapcoltyp := colType(cType)// 5初始化列值接收变量row := make([]sql.RawBytes, len(columns))scanArgs := make([]interface{}, len(row))for i := range row {scanArgs[i] = &row[i]}// 查询结果数据集var dataset []map[string]interface{} //元素为map的切片for rows.Next() {err := rows.Scan(scanArgs...)if err != nil {panic(err.Error())}// rowvar row1 map[string]interface{} = make(map[string]interface{})for pos, col := range row {//fmt.Println(columns[pos], ":", string(col))colname := columns[pos]svalue := string(col)//数据类型处理value := typeConv(colname, svalue, coltyp)row1[colname] = value}//fmt.Println("row1:", row1)dataset = append(dataset, row1)//fmt.Println()}if err != io.EOF {dieOnError("Can't Next", err)}//切片转jsonjsonBytes, err := json.Marshal(dataset)dieOnError("slice 转 json失败:", err)//fmt.Println(string(jsonBytes))return string(jsonBytes)
}// 生成列名和类型 map
func colType(cType []*sql.ColumnType) map[string]string {var colTyp map[string]string = make(map[string]string)for _, col := range cType {colTyp[col.Name()] = col.DatabaseTypeName()}//fmt.Println(colTyp)return colTyp
}// 字符根据数据库类型转为go数据类型
func typeConv(colname string, svalue string, ct map[string]string) interface{} {var ret interface{}switch ct[colname] {case "VARCHAR":ret = svaluecase "DECIMAL":if len(svalue) > 0 {flt, err := strconv.ParseFloat(svalue, 64)if err != nil {fmt.Println("转换失败:", colname, svalue, err)} else {ret = flt}} else { //空串处理ret = nil}default:ret = svalue}return ret
}
运行结果截图:

完
相关文章:
【REST2SQL】07 GO 操作 Mysql 数据库
【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 MySQL是一个关系型数据库管理系统…...
[UI5] ODATA V4中的CRUD
文章目录 前言一、Read二、Create三、Update四、Delete 前言 ODATA V4在CRUD方面与V2截然不同。 这篇文章简单介绍V4中是如何进行CRUD操作 一、Read Model不再有read方法, 一般是把Path绑定到View中进行读取, 如果需要额外的读取数据,可使用…...
js封装根据年月日获取星座效果demo(整理)
//根据年月日获取星座 function getZodiacSign(dateString) {// 用法:const dateStr 2024-01-11;// const zodiacSign getZodiacSign(dateStr);const date new Date(dateString);const month date.getMonth() 1;const day date.getDate();if ((month 1 && day &…...
Vue.js设计与实现阅读-2
Vue.js设计与实现阅读-2 1、前言2、框架设计的核心要素2、1 提升用户体验2、2 控制代码体积2、3 Tree-Shaking2、4 特性开关2、5 错误处理 1、前言 上一篇我们了解到了 命令式和声明式的区别,前者关注过程,后者关注结果了解了虚拟dom存在的意义&#x…...
GEM5 McPAT教程:源代码解读McPAT NoC功耗 arbiter部分
简介 McPAT用的很多,大多只是写个python或perl脚本替换xml文件.没有深入到为什么xml脚本这些值要换,以及这写填进去xml的值是怎么影响计算的.本问从源代码一步步读下来,解释每一步是如何计算的. power 构成: 动态功耗其实更相关于energy McPAT的power 核心是两类,动态和静态…...
使用组合框QComboBox模拟购物车
1.组合框: QComboBox 组合框:QComboBox 用于存放一些列表项 实例化 //实例化QComboBox* comboBox new QComboBox(this);1.1 代码实现 1.1.1 组合框的基本函数 QComboBox dialog.cpp #include "dialog.h" #include "ui_dialog.h"Dialog::Dialog…...
云服务器十大服务商——云服务器哪家好用
云服务器哪家便宜?2024最新整理你要的都在这!头部云厂商阿里云、腾讯云、华为云、京东云、UCloud等都在降价,阿腾云atengyun.com分享2024年云服务器租用价格给你惊喜! 便宜云服务器阿里云腾讯云华为云 2024年便宜云服务器汇总&…...
SQL DML
# DML—添加数据 1.给指定字段添加数据 INSERT INTO表名(字段名1,字段名2,...)VALUES(值1,值2...); 2.给全部字段添加数据 INSERT INTO表名VALUES(值1,值2,...); 3.批量添加数据 INSERT INTO表名(字段名1,字段名2,...)VALUES(值1,值2..…...
MySQL--基础篇
这里写目录标题 总览MySQl各个阶段基础篇总览 MySQL概述数据库相关概念查看本机MySQL版本号启停mysql打开windows服务管理windows命令行启停 连接mysql客户端mysql运行逻辑数据模型关系型数据库 总结 SQL总览SQL通用语法SQL语句分类DDL数据库操作表操作查询表创建表结构数据类型…...
[VUE]5-TypeScript
目录 1 TypeScript 介绍2、安装3、快速上手4、TypeScript 常用类型4.1 类型标注的位置4.2 字符串、数字、布尔类型4.3 字面量类型4.4 ⭐interface 类型4.5 class 类型 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主,…...
Linux指令(一)
今天来学习Linux的一些基本的指令。 今天要学习的指令有ls,pwd,mkdir,cd,touch,rm等。 指令的格式 在Linux中,指令的语法通常遵循以下格式: command [options] [arguments] command 是要执行…...
C语言中的回文素数
任意的整数,当从左向右读与从右向左读是相同的,且为素数时,称为回文素数。求 1000 以内的所有回文素数。 算法思想 实例的重点是判断一个数是否是回文素数。要输出 1000 以内的所有回文素数,首先应判断这个数是否是素数…...
前端生成pdf之html2canvas+jsPDF,以及解决图片不显示bug
前端如何生成pdf 开发背景: 需要给页面中相应的内容生成pdf,查找文档后发现要用到两个插件。html2canvas 以及 jsPDF html2canvas 给dom结构转化为canvas,然后生成各种类型图片jsPDF 把canvas 生成的图片url 转化为pdf // 插入图片 pdf.addI…...
PHP常用符号和函数
// 单行注解 /* */ 多行注解 引号的使用 ’ ’ 单引号,没有任何意义,不经任何处理直接拿过来; ” “双引号,php动态处理然后输出,一般用于变量. 变量形态: 一种是True 即 真的; 另一种是False 即假的 常见变量形态: string 字串(数字\汉字\等等) integer 整数(1、2、…...
C#,入门教程(12)——数组及数组使用的基础知识
上一篇: C#,入门教程(11)——枚举(Enum)的基础知识和高级应用https://blog.csdn.net/beijinghorn/article/details/123917587 数组是一种数据集合,是一组完全相同的、按顺序存放的数据。 需要记住数组的几个特征&…...
C语言中的副作用、序列点以及复杂表达式的求值顺序
C语言中复杂表达式的求值顺序 num (5 2) * (9 * 6);如果我问你:上面的c程序在执行的时候到底是先算(5 2)还是(9 * 6)?你会怎么回答? 无非就两种:先算(5 2ÿ…...
C++学习笔记——队列模拟
目录 一、模拟队列 二、模拟队列的知识点 三、队列 3.1入队操作 3.2出队操作 3.3访问队首元素 3.4访问队尾元素 3.5判断队列是否为空 3.6获取队列的大小 四、实现队列的基本功能 一、模拟队列 当涉及到数据存储和处理时,队列是一种常见的数据结构&#x…...
jvm垃圾回收相关的算法
什么是垃圾 JVM主要通过以下几种方式来判断对象是否需要回收: 引用计数法:JVM通过引用计数器来判断对象的引用数量,当引用数量为0时,表示对象可以被回收。 可达性分析算法:JVM通过根对象(如栈中的引用、静…...
每日coding
2085、统计出现过一次的公共字符串 给你两个字符串数组 words1 和 words2 ,请你返回在两个字符串数组中 都恰好出现一次 的字符串的数目。 示例 1: 输入:words1 ["leetcode","is","amazing","as"…...
软件工程_复习
软件工程 软件危机(1968 60年代) 产生软件危机的原因: 一方面与软件本身的特点有关,另一方面也和软件开发和维护的方法不正确有关。 与软件本身特点有关: 1.软件不同于硬件,软件是计算机系统中的逻辑部件,缺乏“可见性”,管理和控制软件开发过程相当困难 2.软件在运行过…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...
