Go语言操作数据库及其常规操作的示例代码
Go操作MySQL
安装: go get -u github.com/go-sql-driver/mysql
GO语言的操作数据库的驱动原生支持连接池, 并且是并发安全的 标准库没有具体的实现 只是列出了一些需要的第三方库实现的具体内容
//第一次连接MySQL成功 package main import ( "database/sql" _ "github.com/go-sql-driver/mysql" // _想当于init()初始化 "log" ) func main() { // root 用户名 1qa2ws3ed是密码 后边的书ip:port gouse 库名 dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse" db, err := sql.Open("mysql", dsn) if err != nil { panic(err) } // ping是尝试连接MySQL数据库 if err = db.Ping(); err != nil{ panic(err) } log.Fatalln("Mysql数据库连接成功") }
Go调用MySQL封装成函数
package main import ( "database/sql" "encoding/json" "fmt" _ "github.com/go-sql-driver/mysql" ) var db *sql.DB func InitDB() (err error) { dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse" db, err = sql.Open("mysql", dsn) CheckErr(err) err = db.Ping() CheckErr(err) fmt.Println("数据库连接成功...") // 设置数据库连接池最大连接数 db.SetConnMaxLifetime(10) //设置最大闲置连接数 db.SetMaxIdleConns(5) return } type data struct { Username string `json:"username"` Password string `json:"password"` } func main() { err := InitDB() CheckErr(err) query, err := db.Query("select username, password from test") CheckErr(err) for query.Next(){ line := data{} // 查询数据的时候必须要调用scan方法如果 没有 使用scan 连接通道一直保持连接 无法释放连接 _ = query.Scan(&line.Username, &line.Password) fmt.Println(line) dataDic := map[string]string{ "username": line.Username, "password": line.Password, } marshal, _ := json.Marshal(dataDic) fmt.Println(string(marshal)) } } func CheckErr(err error) { if err != nil { fmt.Println(err) panic(err) } }
GO—MySQL的增删改查
package main import ( "database/sql" "encoding/json" "fmt" "time" _ "github.com/go-sql-driver/mysql" ) var db *sql.DB // InitDB 数据库连接初始化 func InitDB() (err error) { dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse" db, err = sql.Open("mysql", dsn) CheckErr(err) err = db.Ping() CheckErr(err) fmt.Println("数据库连接成功...") // 设置数据库连接池最大连接数 db.SetConnMaxLifetime(10) //设置最大闲置连接数 db.SetMaxIdleConns(5) return } type data struct { Username string `json:"username"` Password string `json:"password"` } // SelectQuery 查询函数 func SelectQuery() { sqlStr := "select username, password from test where id > ?" query, err := db.Query(sqlStr, 1) CheckErr(err) defer query.Close() fmt.Printf("现在是北京时间 %s , 你今天进步了吗?\n", time.Now().Format("2006-01-02 15:04:05")) for query.Next() { line := data{} // 查询数据的时候必须要调用scan方法如果 没有 使用scan 连接通道一直保持连接 无法释放连接 _ = query.Scan(&line.Username, &line.Password) //fmt.Println(line) dataDic := map[string]string{ "username": line.Username, "password": line.Password, } marshal, _ := json.Marshal(dataDic) fmt.Printf("查询到的数据为 %s\n", string(marshal)) } } // InsertQuery 插入数据 func InsertQuery() { // sql 语句 sqlStr := `insert into test (username,password) values ("kuQi", "123qwe")` result, err := db.Exec(sqlStr) CheckErr(err) id, err := result.LastInsertId() CheckErr(err) fmt.Printf("插入成功数据的id为 %v", id) } // UpdateQuery 更新数据函数 func UpdateQuery(dataField string, user string) { sqlStr := `update test set password=? where username=?` result, err := db.Exec(sqlStr, dataField, user) CheckErr(err) rowsAffected, err := result.RowsAffected() CheckErr(err) fmt.Printf("被更新字段的id为%d\n", rowsAffected) } // DeleteQuery 删除 func DeleteQuery(id int) { sqlStr := `delete from test where id=?` result, err := db.Exec(sqlStr, id) CheckErr(err) rowsAffected, err := result.RowsAffected() CheckErr(err) if rowsAffected == 0 { fmt.Printf("没有匹配到要删除的id=%d数据", id) return } fmt.Printf("删除数据库的id为%d", id) } //CheckErr 异常捕获函数 func CheckErr(err error) { if err != nil { fmt.Println(err) panic(err) } } // main 主函数 所有函数的入口 func main() { err := InitDB() CheckErr(err) //InsertQuery() UpdateQuery("hahaGolang123", "kuQi") SelectQuery() DeleteQuery(5) }
MySQL的预处理
什么是预处理?
普通SQL语句执行过程:
1.客户端对SQL语句进行占位符的替换得到了完整的SQL语句
2.客户端发送完整SQL语句到MySQL服务端
3.MySQL服务端执行完整的SQL语句并将结果返回终端
预处理的执行过程
1.先把SQL语句拆分成两部分,SQL语句部分和参数部分
2.先把SQL语句部分发送给MySQL服务端进行SQL预处理
3.然后参数部分发送给MySQL服务端,MySQL对SQL语句进行拼接
4.MySQL服务端执行完整的SQL语句返回结果
为什么要进行预处理?
1.为了优化MySQL服务器重复执行SQL的方法。可以执行服务器的性能,提前让服务器编译,一次编译多次执行,节省后续重复编译的成本
2.并且避免SQL注入
Go实现MySQL预处理
// prepare方法现将SQL发送到MySQL服务端, 返回一个准备好的状态用于之后的查询和命令。返回值可以同时执行多个查询和命令 ; 命令也就是SQL语句 // PrepareInsert 预处理执行插入语句 func PrepareInsert() { defer wg.Done() sqlStr := `insert into test (username, password) values (?, ?)` // - 预处理 stmt 就是编译好的sql语句 之后直接传递参数即可 stmt, err := db.Prepare(sqlStr) var u1 = uuid.Must(uuid.NewV4()) CheckErr(err) defer stmt.Close() i := rand.Int() username := fmt.Sprintf("yonghuming%d", i) result, err := stmt.Exec(username, u1.String()[:10]) CheckErr(err) rowsAffected, err := result.LastInsertId() CheckErr(err) fmt.Printf("成功插入id=%d条数据\n", rowsAffected) }
Go语言实现MySQL实现事务操作
// go语言中使用一下三个方法实现MySQL中的事务操作, 开始事务 func (db *DB) Begin()(*Tx, error) // 提交事务 相当与Python中的conn.commit() func (tx *Tx) Commit() error // 回滚事务 func (tx *Tx) Rollback() error package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" ) var db *sql.DB type data struct { Username string `json:"username"` Password string `json:"password"` } // InitDB 数据库连接初始化 func InitDB() (err error) { dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse" db, err = sql.Open("mysql", dsn) CheckErr(err) err = db.Ping() CheckErr(err) fmt.Println("数据库连接成功...") // 设置数据库连接池最大连接数 db.SetMaxOpenConns(100) //设置最大闲置连接数 db.SetMaxIdleConns(5) return } //CheckErr 异常捕获函数 func CheckErr(err error) { if err != nil { fmt.Println(err) panic(err) } } // TranSaCtIon MySQL的事务操作 func TranSaCtIon() { // 开启事务 tx, err := db.Begin() CheckErr(err) // 执行多个SQL操作 sqlStr := `update test set id=id+100000 where password=?` result, err := tx.Exec(sqlStr, "07f70f7e-4") CheckErr(err) id, err := result.LastInsertId() if err != nil { // 语句回滚 err := tx.Rollback() fmt.Println("事务回滚") CheckErr(err) } fmt.Printf("修改后的id为%d\n", id) } func main() { err := InitDB() CheckErr(err) TranSaCtIon() }
sqlx使用
第三方库sqlx能够简化操作,提高开发效率
安装go get github.com/jmoiron/sqlx
package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) var db *sqlx.DB // InitDB 数据库初始化 func InitDB() (err error) { dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse" db, err = sqlx.Connect("mysql", dsn) CheckErr(err) db.SetMaxOpenConns(50) db.SetMaxIdleConns(10) fmt.Println("goUse 数据库连接成功") return } //CheckErr 异常捕获函数 func CheckErr(err error) { if err != nil { fmt.Println(err) panic(err) } } func main() { err := InitDB() CheckErr(err) }
sqlx相较于原生的sql库好处在于 查询的时候sql原生的需要next scan 回调获取结果
sqlx 查询只需要定义一个存储的变量 然后自动就会将查询的出来的值放入变量中
package main import ( "encoding/json" "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) var db *sqlx.DB type user struct { ID int `json:"id"` Username string `json:"username"` Password string `json:"password"` } // InitDB 数据库初始化 func InitDB() (err error) { dsn := "root:1qa2ws3ed@tcp(127.0.0.1:3306)/gouse" // Connect 就是连接的同时db.ping()一下 db, err = sqlx.Connect("mysql", dsn) CheckErr(err) db.SetMaxOpenConns(50) db.SetMaxIdleConns(10) fmt.Println("goUse 数据库连接成功") return } // SelectDB 查询单条数据的方法 func SelectDB() { sqlStr := `select * from test where id=?` var data user _ = db.Get(&data, sqlStr, 990) //CheckErr(err) fmt.Printf("%#v\n", data) marshal, err := json.Marshal(data) CheckErr(err) fmt.Println(string(marshal)) } // ManySelect 查询多条数据方法 func ManySelect() { sqlStr := `select * from test where id < ?` var dataList []user err := db.Select(&dataList, sqlStr, 1000) CheckErr(err) //fmt.Println(dataList) marshal, err := json.Marshal(dataList) CheckErr(err) fmt.Println(string(marshal)) } //CheckErr 异常捕获函数 func CheckErr(err error) { if err != nil { fmt.Println(err) panic(err) } } func main() { err := InitDB() CheckErr(err) SelectDB() ManySelect() }
Go操作Redis
安装go get -u github.com/go-redis/redis
package main import ( "fmt" "github.com/go-redis/redis" ) var redisDB *redis.Client // InitRedisDB redis数据库初始化 func InitRedisDB() (err error) { redisDB = redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "", DB: 0, }) _, err = redisDB.Ping(redisDB.Context()).Result() CheckErr(err) fmt.Println("redis 连接成功") return } //CheckErr 异常捕获函数 func CheckErr(err error) { if err != nil { fmt.Println(err) panic(err) } } func main() { _ = InitRedisDB() }
- set(key, value):给数据库中名称为key的string赋予值value
- get(key):返回数据库中名称为key的string的value
- getset(key, value):给名称为key的string赋予上一次的value
- mget(key1, key2,…, key N):返回库中多个string的value
- setnx(key, value):添加string,名称为key,值为value
- setex(key, time, value):向库中添加string,设定过期时间time
- mset(key N, value N):批量设置多个string的值
- msetnx(key N, value N):如果所有名称为key i的string都不存在
- incr(key):名称为key的string增1操作
- incrby(key, integer):名称为key的string增加integer
- decr(key):名称为key的string减1操作
- decrby(key, integer):名称为key的string减少integer
- append(key, value):名称为key的string的值附加value
- substr(key, start, end):返回名称为key的string的value的子串
NSQ分布式消息队列
NSQ是目前比较流行的一个分布式消息队列,下面主要是NSQ及GO语言如何操作NSQ
NSQ是GO语言编写的一个开源的实时分布式内存消息队列, 其性能十分优异, NSQ的优势有:
1.NSQ提倡分布式和扩散的拓扑,没有单点故障,支持容错和高可用性,并提供可靠的消息交付保证
2.NSQ支持横向扩展, 没有任何集中式代理
3.NSQ易于配置和部署,并且内置了管理界面
安装go get -u github.com/nsqio/go-nsq
Context
在Go HTTP 包的server中,每一个请求都在对应着一个响应,请求处理函数通常会启动额外的goroutine用来访问后端的服务,比如数据库和rpc服务,用来处理一个请求的goroutine通常需要访问一些与请求特定的数据,比如终端的身份认证信息、验证相关的token、请求和截止时间。当一个请求被取消或超时时,所有用来处理该请求的goroutine都应该迅速退出,然后系统才能释放这些goroutine
如何优雅的结束goroutine释放资源
// 通道版本 package main import ( "fmt" "sync" "time" ) var wg sync.WaitGroup func worker(exitChan <-chan struct{}) { defer wg.Done() Test: for { fmt.Println("worker") time.Sleep(time.Second) select { case <-exitChan: break Test default: } } } func main() { wg.Add(1) c := make(chan struct{}) go worker(c) time.Sleep(10 * time.Second) c <- struct{}{} close(c) wg.Wait() fmt.Println("Over") }
// Context版本 package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup func worker(ctx context.Context) { defer wg.Done() Test: for { fmt.Println("worker") time.Sleep(time.Second) select { case <-ctx.Done(): break Test default: } } } func main() { wg.Add(1) ctx, cancelFunc := context.WithCancel(context.Background()) go worker(ctx) time.Sleep(10 * time.Second) cancelFunc() wg.Wait() fmt.Println("Over") }
如果goroutine开启了新的goroutine,只需要将ctx传入到新的goroutine中即可
Background() 和 TODO()
go内置两个函数: Background() 和TUDO(),这两个函数分别返回了一个实现了context接口的background和todo. 我们代码中最开始都是以这两个内置的上下文对象作为最顶层的partent context,衍生出更多的子上下文对象。
backgroud() 主要用于main函数,初始化以及代码测试,作为context这个树结构的最顶层context,也就是跟context。
todo(),他目前还不知道能干点啥?
使用context的注意事项
- 推荐以参数显示传递context
- 以context作为参数的函数方法,应该把context作为第一个参数
- 给一个函数传递context的时候,不要nil,如果不知道传递什么,就使用context.TODO()
- context是并发安全的,可以随意在多个goroutine中传递
log标准库
log包定义了Logger类型, 该类型提供了一些格式化输出的方法。本包也提供了一个预定义的标准logger,可以通过调用函数Print系列,fatal系列和panic系列来使用,比自行创建的logger对象更容易使用。
package main import "log" func main() { log.Println("这是第一条工作日志") v := "THIS is worker log" log.Printf("%#v\n", v) // Fatal将会值写入信息之后,执行exit(1) log.Fatal("之后写一万行代码 我也不执行了哦") // 可以通过log.Panic 引发异常 会将日志写入之后引发异常 log.Panic("测试panic的日志") }
flag选项(日志输出内容设置)
log标准库提供了如下的flag选项,他们是一系列定义好的常量。
const ( Ldate = 1 << iota Ltime Lmicroseconds Llongfile Lshortfile LUTC LstdFlags = Ldate | Ltime ) package main import "log" func main() { // 设置默认附加的内容 log.SetFlags(log.Llongfile | log.Ltime) // 设置日志前缀 log.SetPrefix("[go_log] ") log.Println("测试日志") } output>>> [go_log] 19:02:14 /Users/mac/GolandProjects/src/day02/go_log库/main.go:19: 测试日志
配置日志输出位置
setoutput函数用来设置logger的输出目的地,默认是标准错误输出
package main import ( "log" "os" ) func main() { file, err := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { log.Panic("文件打开失败") } // 设置了写入文件 日志内容就不会打印到终端了 log.SetOutput(file) log.SetFlags(log.Llongfile | log.Ltime) log.SetPrefix("[go_log] ") log.Println("测试日志") }
我们可以定义一个init初始化函数 将log全部配置好 这样更加标准化
第三方日志库logrus的使用
logrus是GO结构化的logger 与上边的logger标准库完全兼容
安装logrusgo get github.com/sirupsen/logrus
package main import ( log "github.com/sirupsen/logrus" ) func main() { log.WithFields(log.Fields{ "animals": "dog", "time": log.FieldKeyTime, }).Info("这是啥") }
日志级别
Trace、debug、info、warning、error、fatal、panic
log.Trace("跟踪?") log.Debug("Debug?") log.Info("信息") log.Warn("警告?") log.Error("Something failed but I'm not quitting.") // 记完日志后会调用os.Exit(1) log.Fatal("Bye.") // 记完日志后会调用 panic() log.Panic("I'm bailing.")
日志记录
package main import ( "os" "time" log "github.com/sirupsen/logrus" ) func main() { file, err := os.OpenFile("logrustest.log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) if err != nil { log.Panicln(err) } log.SetOutput(file) for i := 0; i < 100; i++ { log.WithFields(log.Fields{ "animals": "dog", "Countey": "China", "City": "BeiJing", }).Info("这是啥") time.Sleep(time.Second) } log.Trace("跟踪?") log.Info("信息") log.Warn("警告?") // 设置日志级别, 会记录info以上级别(warn error fatal panic) log.SetLevel(log.InfoLevel) } >>>结果 time="2021-02-04T12:00:15+08:00" level=info msg="这是啥" City=BeiJing Countey=China animals=dog time="2021-02-04T12:00:17+08:00" level=info msg="这是啥" City=BeiJing Countey=China animals=dog time="2021-02-04T12:00:18+08:00" level=info msg="这是啥" City=BeiJing Countey=China animals=dog time="2021-02-04T12:00:19+08:00" level=info msg="这是啥" City=BeiJing Countey=China animals=dog
日志的条目除了使用withfield 和withfields添加的相关日志,还有一些默认添加的日志字段
time 记录日志的时间戳 msg 记录日志信息 level记录日志级别
日志格式化
logrus内置一下两种日志格式化程序
logrus.TextFormatter logrus.JSONFormatter
log.SetFormatter(&log.JSONFormatter{})
追踪函数
log.SetReportCaller(true)
这样就会将哪个文件哪一行 都记录下来 但是不是特殊需求无需开启这个 因为会增加性能开
到此这篇关于Go语言操作数据库及其常规操作的示例代码的文章就介绍到这了,更多相关Go语言操作数据库内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 以前我们开发大型项目时都会用到svn来同步,因为开发产品的人过多,所以我们会利用软件来管理,今天发有一居然可以利用php来管理svn哦,好了看看吧。 代码如下 ...2016-11-25
- 操作类就是把一些常用的一系列的数据库或相关操作写在一个类中,这样调用时我们只要调用类文件,如果要执行相关操作就直接调用类文件中的方法函数就可以实现了,下面整理了...2016-11-25
- 本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 这篇文章主要介绍了Intellij IDEA连接Navicat数据库的方法,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借价值,需要的朋友可以参考下...2021-03-25
- 在开发过程中,我们经常会将日期时间的毫秒数存放到数据库,但是它对应的时间看起来就十分不方便,我们可以使用一些函数将毫秒转换成date格式。 一、 在MySQL中,有内置的函数from_unixtime()来做相应的转换,使用如下: 复制...2014-05-31
- C#使用System.IO中的文件操作方法在Windows系统中处理本地文件相当顺手,这里我们还总结了在Oracle中保存文件的方法,嗯,接下来就来看看整理的C#操作本地文件及保存文件到数据库的基本方法总结...2020-06-25
- 这篇文章主要介绍了Go语言压缩和解压缩tar.gz文件的方法,实例分析了使用Go语言压缩文件与解压文件的技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-05-03
- 通过内网连另外一台机器的mysql服务, 确发现速度N慢! 等了大约几十秒才等到提示输入密码。 但是ping mysql所在服务器却很快! 想到很久之前有过类似的经验, telnet等一些服务在连接请求的时候,会做一些反向域名解析(如果...2015-10-21
- 某些时候,例如为了搭建一个测试环境,或者克隆一个网站,需要复制一个已存在的mysql数据库。使用以下方法,可以非常简单地实现。假设已经存在的数据库名字叫db1,想要复制一份,命名为newdb。步骤如下:1. 首先创建新的数据库newd...2015-10-21
- mysqldump命令的用法1、导出所有库系统命令行mysqldump -uusername -ppassword --all-databases > all.sql 2、导入所有库mysql命令行mysql>source all.sql; 3、导出某些库系统命令行mysqldump -uusername -ppassword...2015-10-21
- 这篇文章介绍了在C#中对config文件的操作,有需要的朋友可以参考一下...2020-06-25
- 1005:创建表失败1006:创建数据库失败1007:数据库已存在,创建数据库失败1008:数据库不存在,删除数据库失败1009:不能删除数据库文件导致删除数据库失败1010:不能删除数据目录导致删除数据库失败1011:删除数据库...2013-09-23
- 这篇文章主要介绍了python自动化办公操作PPT的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-05
- 这篇文章主要介绍了c#从数据库里取得数据并异步更新ui的方法,大家参考使用吧...2020-06-25
- 这篇文章主要介绍了node.js如何操作MySQL数据库,帮助大家更好的进行web开发,感兴趣的朋友可以了解下...2020-10-29
- yii2.0框架是PHP开发的一个比较高效率的框架,集合了作者的大量心血,下面通过用户为例给大家详解yii2使用中的一些基本的增删改查操作。 User::find()->all(); //返回所有用户数据; User::findOne($id); //返回 主键...2015-11-24
nodejs文件操作模块FS(File System)常用函数简明总结
件系统操作相关的函数挺多的。首先可以分为两大类。一类是异步+回调的。 一类是同步的。在这里只对异步的进行整理,同步的只需要在函数名称后面加上Sync即可1. 首先是一类最常规的读写函数,函数名称和形式,应该是起源于C...2014-06-07- 1.用phpmyadmin创建数据库和数据表 创建数据库的时候,请将“整理”设置为:“utf8_general_ci” 或执行语句: 复制代码 代码如下:CREATE DATABASE `dbname` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 创...2015-10-21
- 这篇文章主要介绍了springBoot 项目排除数据库启动方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-10