golang操作mysql使用总结

https://www.cnblogs.com/hanyouchun/

讲解的很详细~

前言

Golang 提供了database/sql包用于对SQL数据库的访问, 作为操作数据库的入口对象sql.DB, 主要为我们提供了两个重要的功能:

  • sql.DB 通过数据库驱动为我们提供管理底层数据库连接的打开和关闭操作.
  • sql.DB 为我们管理数据库连接池

需要注意的是,sql.DB表示操作数据库的抽象访问接口,而非一个数据库连接对象;它可以根据driver打开关闭数据库连接,管理连接池。正在使用的连接被标记为繁忙,用完后回到连接池等待下次使用。所以,如果你没有把连接释放回连接池,会导致过多连接使系统资源耗尽。

操作mysql

1.导入mysql数据库驱动

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

通常来说, 不应该直接使用驱动所提供的方法, 而是应该使用 sql.DB, 因此在导入 mysql 驱动时, 这里使用了匿名导入的方式(在包路径前添加 _), 当导入了一个数据库驱动后, 此驱动会自行初始化并注册自己到Golang的database/sql上下文中, 因此我们就可以通过 database/sql 包提供的方法访问数据库了.

2.连接数据库

123456789101112131415161718
type DbWorker struct {    //mysql data source name Dsn string }

func main() { dbw := DbWorker{ Dsn: "user:password@tcp(127.0.0.1:3306)/test", }  db, err := sql.Open("mysql", dbw.Dsn) if err != nil { panic(err) return } defer db.Close()}

通过调用sql.Open函数返回一个sql.DB指针; sql.Open函数原型如下:

1
func Open(driverName, dataSourceName string) (*DB, error)
  • driverName: 使用的驱动名. 这个名字其实就是数据库驱动注册到 database/sql 时所使用的名字.
  • dataSourceName: 数据库连接信息,这个连接包含了数据库的用户名, 密码, 数据库主机以及需要连接的数据库名等信息.
  1. sql.Open并不会立即建立一个数据库的网络连接, 也不会对数据库链接参数的合法性做检验, 它仅仅是初始化一个sql.DB对象. 当真正进行第一次数据库查询操作时, 此时才会真正建立网络连接;
  2. sql.DB表示操作数据库的抽象接口的对象,但不是所谓的数据库连接对象,sql.DB对象只有当需要使用时才会创建连接,如果想立即验证连接,需要用Ping()方法;
  3. sql.Open返回的sql.DB对象是协程并发安全的.
  4. sql.DB的设计就是用来作为长连接使用的。不要频繁Open, Close。比较好的做法是,为每个不同的datastore建一个DB对象,保持这些对象Open。如果需要短连接,那么把DB作为参数传入function,而不要在function中Open, Close。

3.数据库基本操作

数据库查询的一般步骤如下:

  1. 调用 db.Query 执行 SQL 语句, 此方法会返回一个 Rows 作为查询的结果
  2. 通过 rows.Next() 迭代查询数据.
  3. 通过 rows.Scan() 读取每一行的值
  4. 调用 db.Close() 关闭查询

现有user数据库表如下:

123456
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT '', `age` int(11) DEFAULT '0', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4
MySQL 5.5 之前, UTF8 编码只支持1-3个字节,从MYSQL5.5开始,可支持4个字节UTF编码utf8mb4,一个字符最多能有4字节,utf8mb4兼容utf8,所以能支持更多的字符集;关于emoji表情的话mysql的utf8是不支持,需要修改设置为utf8mb4,才能支持。

查询数据

12345678910111213141516171819202122232425262728
func (dbw *DbWorker) QueryData() { dbw.QueryDataPre()    rows, err := dbw.Db.Query(`SELECT * From user where age >= 20 AND age < 30`)    defer rows.Close() if err != nil { fmt.Printf("insert data error: %v\n", err) return } for rows.Next() { rows.Scan(&dbw.UserInfo.Id, &dbw.UserInfo.Name, &dbw.UserInfo.Age) if err != nil { fmt.Printf(err.Error()) continue } if !dbw.UserInfo.Name.Valid { dbw.UserInfo.Name.String = "" } if !dbw.UserInfo.Age.Valid { dbw.UserInfo.Age.Int64 = 0 } fmt.Println("get data, id: ", dbw.UserInfo.Id, " name: ", dbw.UserInfo.Name.String, " age: ", int(dbw.UserInfo.Age.Int64)) }

 err = rows.Err() if err != nil { fmt.Printf(err.Error()) }}
  1. rows.Scan 参数的顺序很重要, 需要和查询的结果的column对应. 例如 “SELECT * From user where age >=20 AND age < 30” 查询的行的 column 顺序是 “id, name, age” 和插入操作顺序相同, 因此 rows.Scan 也需要按照此顺序 rows.Scan(&id, &name, &age), 不然会造成数据读取的错位.
  2. 因为golang是强类型语言,所以查询数据时先定义数据类型,但是查询数据库中的数据存在三种可能:存在值,存在零值,未赋值NULL 三种状态, 因为可以将待查询的数据类型定义为sql.Nullxxx类型,可以通过判断Valid值来判断查询到的值是否为赋值状态还是未赋值NULL状态.
  3. 每次db.Query操作后, 都建议调用rows.Close(). 因为 db.Query() 会从数据库连接池中获取一个连接, 这个底层连接在结果集(rows)未关闭前会被标记为处于繁忙状态。当遍历读到最后一条记录时,会发生一个内部EOF错误,自动调用rows.Close(),但如果提前退出循环,rows不会关闭,连接不会回到连接池中,连接也不会关闭, 则此连接会一直被占用. 因此通常我们使用 defer rows.Close() 来确保数据库连接可以正确放回到连接池中; 不过阅读源码发现rows.Close()操作是幂等操作,即一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同, 所以即便对已关闭的rows再执行close()也没关系.

单行查询

123456
var name stringerr = db.QueryRow("select name from user where id = ?", 1).Scan(&name)if err != nil { log.Fatal(err)}fmt.Println(name)
  1. err在Scan后才产生,上述链式写法是对的
  2. 需要注意Scan()中变量和顺序要和前面Query语句中的顺序一致,否则查出的数据会映射不一致.

插入数据

12345678910111213
func (dbw *DbWorker) insertData() {    ret, err := dbw.Db.Exec(`INSERT INTO user (name, age) VALUES ("xys", 23)`)   if err != nil { fmt.Printf("insert data error: %v\n", err) return } if LastInsertId, err := ret.LastInsertId(); nil == err { fmt.Println("LastInsertId:", LastInsertId) } if RowsAffected, err := ret.RowsAffected(); nil == err { fmt.Println("RowsAffected:", RowsAffected) }}

通过db.Exec()插入数据,通过返回的err可知插入失败的原因,通过返回的ret可以进一步查询本次插入数据影响的行数RowsAffected和最后插入的Id(如果数据库支持查询最后插入Id).

github完整代码示例

4.预编译语句(Prepared Statement)
预编译语句(PreparedStatement)提供了诸多好处, 因此我们在开发中尽量使用它. 下面列出了使用预编译语句所提供的功能:

  • PreparedStatement 可以实现自定义参数的查询
  • PreparedStatement 通常来说, 比手动拼接字符串 SQL 语句高效.
  • PreparedStatement 可以防止SQL注入攻击

一般用Prepared StatementsExec()完成INSERTUPDATEDELETE操作。

下面是将上述案例用Prepared Statement 修改之后的完整代码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
package main

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

type DbWorker struct { Dsn string Db *sql.DB UserInfo userTB}type userTB struct { Id int Name sql.NullString Age sql.NullInt64}

func main() { var err error dbw := DbWorker{ Dsn: "root:123456@tcp(localhost:3306)/sqlx_db?charset=utf8mb4", } dbw.Db, err = sql.Open("mysql", dbw.Dsn) if err != nil { panic(err) return } defer dbw.Db.Close()

 dbw.insertData() dbw.queryData()}

func (dbw *DbWorker) insertData() { stmt, _ := dbw.Db.Prepare(`INSERT INTO user (name, age) VALUES (?, ?)`) defer stmt.Close()

 ret, err := stmt.Exec("xys", 23) if err != nil { fmt.Printf("insert data error: %v\n", err) return } if LastInsertId, err := ret.LastInsertId(); nil == err { fmt.Println("LastInsertId:", LastInsertId) } if RowsAffected, err := ret.RowsAffected(); nil == err { fmt.Println("RowsAffected:", RowsAffected) }}

func (dbw *DbWorker) QueryDataPre() { dbw.UserInfo = userTB{}}func (dbw *DbWorker) queryData() { stmt, _ := dbw.Db.Prepare(`SELECT * From user where age >= ? AND age < ?`) defer stmt.Close()

 dbw.QueryDataPre()

 rows, err := stmt.Query(20, 30) defer rows.Close() if err != nil { fmt.Printf("insert data error: %v\n", err) return } for rows.Next() { rows.Scan(&dbw.UserInfo.Id, &dbw.UserInfo.Name, &dbw.UserInfo.Age) if err != nil { fmt.Printf(err.Error()) continue } if !dbw.UserInfo.Name.Valid { dbw.UserInfo.Name.String = "" } if !dbw.UserInfo.Age.Valid { dbw.UserInfo.Age.Int64 = 0 } fmt.Println("get data, id: ", dbw.UserInfo.Id, " name: ", dbw.UserInfo.Name.String, " age: ", int(dbw.UserInfo.Age.Int64)) }

 err = rows.Err() if err != nil { fmt.Printf(err.Error()) }}

转载于:https://www.cnblogs.com/jinanxiaolaohu/p/10738859.html

[转帖]golang操作mysql使用总结相关推荐

  1. golang操作mysql用例

    ❤️强烈推荐人工智能学习网站❤️ golang操作mysql的demo,直接上代码 package mainimport ("database/sql""fmt" ...

  2. golang mysql商业用例_完美起航-golang操作mysql用例

    golang操作mysql的demo,直接上代码 package main import ( "database/sql" "fmt" _ "gith ...

  3. mysql操作数据库的步骤,Golang操作MySql数据库的完整步骤记录

    前言 MySQL是业界常用的关系型数据库,在平时开发中会经常与MySql数据库打交道,所以在接下来将介绍怎么使用Go语言操作MySql数据库. 下载MySql连接驱动 Go语言中的database/s ...

  4. 封装一个自己的golang操作MySQL数据库工具

    封装一个自己的golang操作MySQL数据库工具 准备工作 导入驱动 连接mysql 增删改查 增 删 改 查 准备工作 首先我们要准备一个写golang的IDE,我用的是goland,还可以用vs ...

  5. golang操作mysql

    后台开发语言访问数据库,下面看一下golang访问mysql的常见API. sql.Open() //连接数据库 db.Query() //查询 db.QueryRow() //查询一行 db.Exe ...

  6. golang mysql 插入_Mysql学习(一)添加一个新的用户并用golang操作Mysql

    Mysql添加一个新的用户并赋予权限 添加一个自己的用户到mysql 首先我们需要先用root用户登录mysql,但是刚安装完没有密码,我们先跳过密码 ailumiyana@ailumiyana:~/ ...

  7. golang操作mysql数据库(Go-SQL-Driver/MySQL)

    下载安装,执行下面两个命令: 下载:go get github.com/Go-SQL-Driver/MySQL 安装:go install github.com/Go-SQL-Driver/MySQL ...

  8. mysql的gobye_Mysql學習(一)添加一個新的用戶並用golang操作Mysql

    Mysql添加一個新的用戶並賦予權限 添加一個自己的用戶到mysql 首先我們需要先用root用戶登錄mysql,但是剛安裝完沒有密碼,我們先跳過密碼 ailumiyana@ailumiyana:~/ ...

  9. golang 执行sql语句_Go语言学习笔记(Golang操作MySQL数据库)

    GO连接MySQL 通过GO页面作为客户端访问数据库 1.因为GO语言没有提供任何官方数据库驱动,所以需要安装第三方函数库. 2.由于在github上安装,所以需要安装git软件,安装过程一直点击下一 ...

  10. Go语言学习笔记—golang操作MySQL数据库

    文章目录 一 准备数据库和表 二 安装配置mysql驱动 三 获得数据库连接 3.1 导入包 3.2 获得连接 3.3 初始化连接 四 插入数据 五 查询数据 5.1 单行查询 5.2 多行查询 六 ...

最新文章

  1. c#垂直投影法_投影学
  2. 如何对 string 进行Base64编码,解码?
  3. 音频视频解决方案:GStreamer/ffmpeg/ffdshow/directshow/vfw
  4. 面相终端的计算机网络的阶段特征,计算机网络习题汇编
  5. 算法与程序设计_算法与程序设计入门-简单计算题1
  6. PSD分层情人节海报模板,让人眼前一亮
  7. C++中menset用法
  8. mysql 数据库的 导入于导出
  9. PHP版本中的VC6,VC9,VC11,TS,NTS区别
  10. 全世界国家中英文名称以及地区区号json格式【资源】
  11. 多Excel合并成一个Excel的多sheet
  12. 计算机网络信息安全等级保护(等保)
  13. HTML网页上播放AVI视频代码示例
  14. matlab学霸表白公式,一个理科学霸的表白:数学公式的超酷表白
  15. 数据中心的铜缆布线活力无限不过时
  16. Detection with Enriched Semantics(DES)算法笔记
  17. 《2022,自我增值的7个好习惯》读书笔记
  18. Android简单的布局优化
  19. PMBOK(第六版) PMP笔记——《十》第十章(项目沟通管理)
  20. 【Altium Designer 基础操作(上)】

热门文章

  1. 最新!Dubbo 远程代码执行漏洞通告,速度升级
  2. 蚂蚁上市,身边又多了一堆千万富翁!
  3. Android MVP 实例
  4. 《数据库系统概念》19-并发控制
  5. [ios]object-c math.h里的数学计算公式介绍
  6. BZOJ-1069 [SCOI2007]最大土地面积
  7. 《cut命令》-linux命令五分钟系列之十九
  8. AS3.0实例学习 熟悉新的事件机制和addChild的运用
  9. Debit credit problem
  10. C#绘制条码CODE39和CODE39全码模式