Golang操作数据库简单示例
目录
- 准备工作
- 准备数据
- 创建项目
- 连接数据库
- 查询数据
- 修改数据
- 插入数据
- 删除数据
- 释放资源
- 完整代码
- 最终执行结果
准备工作
在开始之前,你需要确保自己安装了Golang的编程环境,安装MySQL数据库,有一个可以用于编写代码的编辑器或IDE工具。我在这里使用的编辑器是Fleet。
准备数据
将下面的SQL语句在MySQL中执行,创建数据库并插入数据.。
drop table if exists album;
create table album (id int auto_increment not null,title varchar(128) not null,artist varchar(255) not null,price decimal(5,2) not null,primary key (`id`)
);
insert into album(title, artist, price)
values('Blue Train', 'John Coltrane', 56.99),('Giant Steps', 'Greey Mulligan', 63.99),('Jeru', 'Gerry Mulligan', 17.99),('Sarah Vaughan', 'Sarah Vaughan', 34.98);
创建项目
进入终端,输入以下命令。(当然,你也可以手动创建)
mkdir data-access
cd ./data-access
go mod init example/data-access
在上面创建的目录下创建文件main.go,将以下代码粘贴到文件中。
package mainimport ("database/sql""errors""fmt""github.com/go-sql-driver/mysql""log"
)
终端输入以下命令下载上面代码中引入的MySQL的驱动包
go mod tidy
连接数据库
在main.go中输入以下代码,连接数据库。
var db *sql.DBfunc main() {// 设置连接属性cfg := mysql.Config{User: "root",Passwd: "123456",Net: "tcp",Addr: "127.0.0.1:3306",DBName: "recordings",}// 获取数据库句柄var err errordb, err = sql.Open("mysql", cfg.FormatDSN())if err != nil {log.Fatal(err)}// 测试是否连接成功pingErr := db.Ping()if pingErr != nil {log.Fatal(pingErr)}log.Println("Connected!")
}
查询数据
对于数据库中的数据,我们需要定义一个结构体去接收。在main.go中输入以下代码。
// Album 记录实体结构体
type Album struct {ID int64Title stringArtist stringPrice float32
}
接着我们实现String函数让输出稍微美观一些。
func (album Album) String() string {return fmt.Sprintf(`{ "id": %d, "title": %q, "artist": %q, "price": %.2f }`, album.ID, album.Title, album.Artist, album.Price)
}
接下来,让我们编写一个函数,这个函数的功能是通过人名去查询数据库中的记录。
// 通过人名查询记录
func albumsByArtist(name string) ([]Album, error) {var albums []Albumrows, err := db.Query("select * from album where artist = ?", name)if err != nil {return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)}// 资源释放,defer关键字修饰的语句在其下方语句未执行完成前不会执行defer rows.Close()// 循环获取相关值for rows.Next() {var alb Albumif err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)}albums = append(albums, alb)}if err := rows.Err(); err != nil {return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)}return albums, nil
}
接着定义一个函数,通过id去查询记录。
// 通过ID查询记录
func albumsById(id int64) (Album, error) {var alb Albumrow := db.QueryRow("select * from album where id = ?", id)if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {if errors.Is(err, sql.ErrNoRows) {return alb, fmt.Errorf("albumsById %d: no such album", id)}return alb, fmt.Errorf("albumsById %d: %v", id, err)}return alb, nil
}
然后,我们在main函数中调用。
// 查询数据
albums, err := albumsByArtist("John Coltrane")
if err != nil {log.Fatal(err)
}
log.Printf("Albums found: %v\n", albums)alb, err := albumsById(2)
if err != nil {log.Fatal(err)
}
log.Printf("Album found: %v\n", alb)
修改数据
我们来定义一个函数用来修改数据,用id做为删选条件。
// 修改数据
func updateAlbumById(alb Album) (int64, error) {result, err := db.Exec("update album set title = ?, artist = ?, price = ? where id = ?", alb.Title, alb.Artist, alb.Price, alb.ID)if err != nil {return 0, fmt.Errorf("updateAlbumById: %v", err)}rows, err := result.RowsAffected()if err != nil {return 0, fmt.Errorf("updateAlbumById: %v", err)}return rows, nil
}
在main函数中调用它。
// 修改数据
updateRows, err := updateAlbumById(Album{ID: 1,Title: "White teddy bear",Artist: "John Thompson's",Price: 20.99,
})
if err != nil {log.Fatal(err)
}
log.Printf("Number of rows updated: %v\n", updateRows)
插入数据
定义一个函数用来插入数据并且返回插入数据在数据库中的id。
// 插入记录
func addAlbum(alb Album) (int64, error) {result, err := db.Exec("insert into album (title, artist, price) values (?, ?, ?)", alb.Title, alb.Artist, alb.Price)if err != nil {return 0, fmt.Errorf("addAlbum: %v", err)}id, err := result.LastInsertId()if err != nil {return 0, fmt.Errorf("addAlbum: %v", err)}return id, nil
}
在main函数中调用
// 插入数据
albId, err := addAlbum(Album{Title: "The Modern Sound of Betty Carter",Artist: "Betty Carter",Price: 49.99,
})
if err != nil {log.Fatal(err)
}
log.Printf("id of added alnum: %v\n", albId)
删除数据
定义一个函数用来删除数据。
// 删除记录,返回删除的行数
func deleteAlbum(id int64) (int64, error) {result, err := db.Exec("delete from album where id = ?", id)if err != nil {return 0, fmt.Errorf("deleteAlbum: %v", err)}rows, err := result.RowsAffected()if err != nil {return 0, fmt.Errorf("deleteAlbum: %v", err)}return rows, nil
}
在main函数中调用
// 删除数据
deleteRows, err := deleteAlbum(albId)
if err != nil {log.Fatal(err)
}
log.Printf("Number of rows deleted: %v\n", deleteRows)
释放资源
对于数据库的操作完成后,需要释放数据库连接,在main函数中输入以下代码释放资源。
// 释放资源
err = db.Close()
if err != nil {log.Fatal(err)
}
完整代码
完整代码如下。
package mainimport ("database/sql""errors""fmt""github.com/go-sql-driver/mysql""log"
)var db *sql.DB// Album 记录实体结构体
type Album struct {ID int64Title stringArtist stringPrice float32
}func (album Album) String() string {return fmt.Sprintf(`{ "id": %d, "title": %q, "artist": %q, "price": %.2f }`, album.ID, album.Title, album.Artist, album.Price)
}func main() {// 设置连接属性cfg := mysql.Config{User: "root",Passwd: "123456",Net: "tcp",Addr: "127.0.0.1:3306",DBName: "recordings",}// 获取数据库句柄var err errordb, err = sql.Open("mysql", cfg.FormatDSN())if err != nil {log.Fatal(err)}// 测试是否连接成功pingErr := db.Ping()if pingErr != nil {log.Fatal(pingErr)}log.Println("Connected!")// 查询数据albums, err := albumsByArtist("John Coltrane")if err != nil {log.Fatal(err)}log.Printf("Albums found: %v\n", albums)alb, err := albumsById(2)if err != nil {log.Fatal(err)}log.Printf("Album found: %v\n", alb)// 修改数据updateRows, err := updateAlbumById(Album{ID: 1,Title: "White teddy bear",Artist: "John Thompson's",Price: 20.99,})if err != nil {log.Fatal(err)}log.Printf("Number of rows updated: %v\n", updateRows)// 插入数据albId, err := addAlbum(Album{Title: "The Modern Sound of Betty Carter",Artist: "Betty Carter",Price: 49.99,})if err != nil {log.Fatal(err)}log.Printf("id of added alnum: %v\n", albId)// 删除数据deleteRows, err := deleteAlbum(albId)if err != nil {log.Fatal(err)}log.Printf("Number of rows deleted: %v\n", deleteRows)// 释放资源err = db.Close()if err != nil {log.Fatal(err)}
}// 通过人名查询记录
func albumsByArtist(name string) ([]Album, error) {var albums []Albumrows, err := db.Query("select * from album where artist = ?", name)if err != nil {return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)}// 资源释放,defer关键字修饰的语句在其下方语句未执行完成前不会执行defer rows.Close()// 循环获取相关值for rows.Next() {var alb Albumif err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)}albums = append(albums, alb)}if err := rows.Err(); err != nil {return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)}return albums, nil
}// 通过ID查询记录
func albumsById(id int64) (Album, error) {var alb Albumrow := db.QueryRow("select * from album where id = ?", id)if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil {if errors.Is(err, sql.ErrNoRows) {return alb, fmt.Errorf("albumsById %d: no such album", id)}return alb, fmt.Errorf("albumsById %d: %v", id, err)}return alb, nil
}// 修改数据
func updateAlbumById(alb Album) (int64, error) {result, err := db.Exec("update album set title = ?, artist = ?, price = ? where id = ?", alb.Title, alb.Artist, alb.Price, alb.ID)if err != nil {return 0, fmt.Errorf("updateAlbumById: %v", err)}rows, err := result.RowsAffected()if err != nil {return 0, fmt.Errorf("updateAlbumById: %v", err)}return rows, nil
}// 插入记录
func addAlbum(alb Album) (int64, error) {result, err := db.Exec("insert into album (title, artist, price) values (?, ?, ?)", alb.Title, alb.Artist, alb.Price)if err != nil {return 0, fmt.Errorf("addAlbum: %v", err)}id, err := result.LastInsertId()if err != nil {return 0, fmt.Errorf("addAlbum: %v", err)}return id, nil
}// 删除记录,返回删除的行数
func deleteAlbum(id int64) (int64, error) {result, err := db.Exec("delete from album where id = ?", id)if err != nil {return 0, fmt.Errorf("deleteAlbum: %v", err)}rows, err := result.RowsAffected()if err != nil {return 0, fmt.Errorf("deleteAlbum: %v", err)}return rows, nil
}
最终执行结果

相关文章:
Golang操作数据库简单示例
目录 准备工作准备数据创建项目连接数据库查询数据修改数据插入数据删除数据释放资源完整代码最终执行结果 准备工作 在开始之前,你需要确保自己安装了Golang的编程环境,安装MySQL数据库,有一个可以用于编写代码的编辑器或IDE工具。我在这里…...
亚马逊测评,买家号支付不了、砍单率高是什么问题,需要怎么解决
下半年旺季很多卖家都在使用自养号测评给产品冲一波权重,但是很多朋友会遇到下不了单或者砍单率过高等问题。有人以为是支付卡的问题,也有人觉得是IP被关联了。其实他们讲的也没错,但是,亚马逊风控不会针对某个点去进行检测&#…...
B. Jellyfish and Game-Codeforces Round 902 (Div. 2)
B. Jellyfish and Game 交换k轮使得第一个同学拥有数值总数最大; 很容易看出这道题需要判断k奇偶数。 当k是奇数时可以看作第一个同学操作一轮。 k为偶数可以看作两个同学各操作一轮。 #include<iostream> #include<vector> #include<algorithm>…...
Linux下的命令行参数和环境变量
命令行参数 什么是命令行参数 命令行参数是指在执行命令行程序时,给程序传递的额外参数。在Linux终端中,命令行参数通常通过在命令后面添加空格分隔的参数来传递。 Linux下以main函数举例说明 #include<stdio.h>int main(int argc char* argv[])…...
语音芯片KT142C两种音频输出方式PWM和DAC的区别
目录 语音芯片KT142C两种音频输出方式PWM和DAC的区别 一般的语音芯片,输出方式,无外乎两种,即dac输出,或者PWM输出 其中dac的输出,一般应用场景都是外挂功放芯片,实现声音的放大,比如常用的音箱…...
Kotlin 协程的挂起和阻塞的区别
一,简介 Kotlin协程引入了非常强大的异步编程模型,通过挂起而不是阻塞来实现并发操作。以下是有关Kotlin协程挂起和阻塞的详细介绍: 挂起(Suspending): 挂起是指一个协程的执行可以在不阻塞线程的情况下暂…...
解决Github Markdown图片显示残缺的问题
title: 解决Github Markdown图片显示残缺的问题 tags: 个人成长 categories:杂谈 在Github存放Markdown文档,如果图片没有存放在Github服务器上,github会尝试生成Github图片缓存,使用Github图片缓存,进行实际的展示。但比较蛋疼的…...
[MAUI]深入了解.NET MAUI Blazor与Vue的混合开发
文章目录 Vue在混合开发中的特点创建MAUI项目创建Vue应用使用element-ui组件库JavaScript和原生代码的交互传递根组件参数从设备调用Javascript代码从Vue页面调用原生代码 读取设备信息项目地址 .NET MAUI结合Vue的混合开发可以使用更加熟悉的Vue的语法代替Blazor语法ÿ…...
1209. 带分数
题目: 1209. 带分数 - AcWing题库 思路: 1.targetab/c,由题意a,b,c会包含1~9 且每个数出现且只能出现一次。我们可以抽象化为9个坑位分成3份分别给a,b,c。 2.先采用递归搜索树写出9个坑位的全排列,再分成3个区,分…...
【树莓派触摸屏等学习笔记】
前言 树莓派触摸屏 提示:以下是本篇文章正文内容,下面案例可供参考 一、触摸屏硬件驱动 出现黑屏的时候,恢复一下txt config.txt 全屏显示 showFull Exec :自启动 surf 算法 特征点识别 算法的复杂度挺高的 特性树莓派强大…...
ERR_PNPM_JSON_PARSE Unexpected end of JSON input while parsing empty string in
终端报错: ERR_PNPM_JSON_PARSE Unexpected end of JSON input while parsing empty string in 报错原因:依赖没有删除干净 解决办法: ①删除node_modules ②在package.json的dependencies删除不需要依赖 ③重新pnpm i...
linux基础IO
文章目录 前言一、基础IO1、文件预备知识1.1 文件类的系统调用接口1.2 复习c语言接口 2、文件类的系统调用接口2.1 open系统调用2.2 close系统调用2.3 write系统调用2.4 read系统调用 3、文件描述符3.1 文件描述符fd介绍3.2 文件描述符fd分配规则与重定向3.3 重定向原理3.4输入…...
华为OD机试 - TLV格式 - 逻辑分析(Java 2023 B卷 100分)
目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷&#…...
LLMs之RAG:利用langchain实现RAG应用五大思路步骤—基于langchain使用LLMs(ChatGPT)构建一个问题回答文档的应用程序实战代码
LLMs之RAG:利用langchain实现RAG应用五大思路步骤—基于langchain使用LLMs(ChatGPT)构建一个问题回答文档的应用程序实战代码 目录 相关文章...
链式队列----数据结构
队列的基本概念 队列是一种操作受限的线性表(先进先出),只允许在队尾插入,队头删除。 例如去银行办理业务,肯定是先来的先出去,后来的人排在后方,只有第一个人业务办理完了,才会有…...
VM虚拟机VMware Fusion(13.5.0)
VMware Fusion提供了在Apple Mac上运行Windows、Linux等操作系统的最佳方式,无需重新启动。Fusion 13支持运行macOS 12及更高版本的Intel和Apple Silicon Mac,并包含面向开发人员、IT管理员和日常用户的功能。 Fusion 13 新增功能 支持新的客户机操作系…...
自动化测试08
Junit 为什么学了Selenium还需学习Junit Selenium自动化测试框架;Junit单元测试框架。 拿着一个技术写自动化测试用例(Selenium3) 拿着一个技术管理已经编写好的测试用例(Junit5) Junit相关的技术 Junit是针对Java的一…...
d3dx9_43.dll丢失有什么办法可以解决,解决d3dx9_43.dll丢失
通常d3dx9_43.dll丢失都是在运行游戏时汤出的d3dx9_43.dll找不到的错误窗口,因为d3dx9_43.dll文件更多是在使用游戏时会被调用的dll文件,d3dx9_43.dll是属于DirectX9的一个组件,DirectX9是游戏系统中的一个重要程序,所以当d3dx9_4…...
【C++】: auto关键字(C++11)+基于范围的for循环(C++11)+指针空值nullptr(C++11)
auto关键字(C11) 随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在: 类型难于拼写含义不明确导致容易出错 #include <string> #include <map> int main() {std::map<std::string, std::…...
华为OD机试 - 玩牌高手 - 动态规划(Java 2023 B卷 100分)
目录 一、题目描述二、输入描述三、输出描述四、解题思路具体规则如下:具体步骤如下: 五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 一、题目描述 给定一个长度为n的整型数组࿰…...
Linux内核驱动开发踩坑记:为什么我的Makefile一编译就报错?原来是-Werror在搞鬼
Linux内核驱动开发实战:当-Werror让编译崩溃时如何精准排雷 深夜两点,屏幕上的红色错误信息格外刺眼——昨天还能正常编译的内核模块,今天突然因为几个"无关紧要"的未使用变量报错退出。这种场景对Linux内核开发者来说再熟悉不过&a…...
5分钟快速搭建乳腺癌预测神经网络教程
1. 项目概述:5分钟快速搭建乳腺癌预测神经网络去年在Kaggle社区看到一个乳腺癌预测比赛时,我意识到很多医疗从业者其实并不需要深入理解神经网络的所有数学细节,他们更关注如何快速验证一个基础模型的效果。这就是为什么我开发了一套极简流程…...
手把手教你用Vector工具链集成AUTOSAR RTM模块,实测CPU负载(含避坑点)
实战指南:Vector工具链集成AUTOSAR RTM模块与CPU负载监控全解析 在嵌入式软件开发领域,特别是汽车电子控制单元(ECU)开发中,实时监控系统资源使用情况是确保软件可靠性的关键环节。当项目周期紧张且资源有限时,如何快速实现CPU负载…...
思源宋体CN终极指南:免费开源中文字体完全使用手册
思源宋体CN终极指南:免费开源中文字体完全使用手册 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还在为中文排版设计寻找专业字体而烦恼吗?思源宋体CN这款由A…...
肿瘤生物标志物的研究热点与前沿技术
摘要:肿瘤标志物在肿瘤早期筛查、辅助诊断、疗效评估及预后判断中的作用日益凸显,已成为肿瘤精准诊疗体系的核心组成部分。本文系深入剖析了以液体活检技术为支撑的ctDNA基因标志物、DNA甲基化、外泌体及循环肿瘤细胞(CTC)等多维度…...
UI前端美化技能提升日志day6:(使用苹果字体+计算样式对比差异)
前端复刻苹果官网实战:今日主要解决的核心卡点问题全复盘 在前端高仿企业级官网落地实战开发中,苹果中国官网复刻项目对UI还原度、字体原生适配、静态资源联动渲染有着极高标准,尤其官网专属定制字体、全局统一视觉基线、页脚精细化布局&…...
别再只盯着MACD了!用Python回测SuperTrend指标在A股的表现到底怎么样?
SuperTrend指标在A股实战中的表现:Python量化回测全解析 当MACD和均线已经成为每个交易者的标配工具时,市场上总有一些"网红指标"声称自己能够提供更清晰的趋势信号。SuperTrend指标就是近年来备受关注的一个——但它在A股市场真的能带来超额收…...
Docker 27资源配额动态调整全链路拆解:从OCI runtime hook到runc v1.2.0配额注入机制(仅限内部技术白皮书级披露)
第一章:Docker 27资源配额动态调整全链路概览Docker 27(即 Docker Engine v27.x)引入了原生支持的运行时资源配额动态重配置能力,无需重启容器即可实时更新 CPU、内存、IO 及 PIDs 等核心限制。该机制依托于 cgroups v2 的可写接口…...
别只盯着门锁!用ESP32-CAM+Arduino玩转5个超酷的人脸识别小项目
用ESP32-CAM玩转5个创意人脸识别项目:从智能相框到互动艺术 在创客圈里,ESP32-CAM正以惊人的性价比重新定义着嵌入式视觉的可能性。这块不足百元的小板子,搭载了双核处理器、WiFi/蓝牙模块和200万像素摄像头,配合Arduino生态的丰富…...
别再死记硬背74HC138真值表了!用Arduino+面包板,5分钟搞懂3-8译码器怎么省IO口
用Arduino实战破解74HC138:3根线控制8个LED的硬件魔法 记得第一次在电子设计课上看到74HC138真值表时,那种面对16进制代码的茫然感至今难忘。直到某天在创客空间,看到有人用Arduino和面包板搭建了一个会"跑马"的LED阵列——只用3根…...
