文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用Golang怎么操作数据库

2023-06-14 14:31

关注

使用Golang怎么操作数据库?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

golang适合做什么

golang可以做服务器端开发,但golang很适合做日志处理、数据打包、虚拟机处理、数据库代理等工作。在网络编程方面,它还广泛应用于web应用、API应用等领域。

Go操作MySQL

安装: go get -u github.com/go-sql-driver/mysql

GO语言的操作数据库的驱动原生支持连接池, 并且是并发安全的 标准库没有具体的实现 只是列出了一些需要的第三方库实现的具体内容

//第一次连接MySQL成功package mainimport ( "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 mainimport ( "database/sql" "encoding/json" "fmt" _ "github.com/go-sql-driver/mysql")var db *sql.DBfunc 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 mainimport ( "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() errorpackage mainimport ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql")var db *sql.DBtype 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 mainimport ( "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 mainimport ( "encoding/json" "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx")var db *sqlx.DBtype 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 mainimport ( "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()}

NSQ分布式消息队列

NSQ是目前比较流行的一个分布式消息队列,下面主要是NSQ及GO语言如何操作NSQ

NSQ是GO语言编写的一个开源的实时分布式内存消息队列, 其性能十分优异, NSQ的优势有:

NSQ提倡分布式和扩散的拓扑,没有单点故障,支持容错和高可用性,并提供可靠的消息交付保证

NSQ支持横向扩展, 没有任何集中式代理

NSQ易于配置和部署,并且内置了管理界面

安装go get -u github.com/nsqio/go-nsq

Context

在Go HTTP 包的server中,每一个请求都在对应着一个响应,请求处理函数通常会启动额外的goroutine用来访问后端的服务,比如数据库和rpc服务,用来处理一个请求的goroutine通常需要访问一些与请求特定的数据,比如终端的身份认证信息、验证相关的token、请求和截止时间。当一个请求被取消或超时时,所有用来处理该请求的goroutine都应该迅速退出,然后系统才能释放这些goroutine

如何优雅的结束goroutine释放资源

// 通道版本package mainimport ( "fmt" "sync" "time")var wg sync.WaitGroupfunc 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 mainimport ( "context" "fmt" "sync" "time")var wg sync.WaitGroupfunc 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的注意事项

log标准库

log包定义了Logger类型, 该类型提供了一些格式化输出的方法。本包也提供了一个预定义的标准logger,可以通过调用函数Print系列,fatal系列和panic系列来使用,比自行创建的logger对象更容易使用。

package mainimport "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 mainimport "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 mainimport ( "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 mainimport ( 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 mainimport ( "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=dogtime="2021-02-04T12:00:17+08:00" level=info msg="这是啥" City=BeiJing Countey=China animals=dogtime="2021-02-04T12:00:18+08:00" level=info msg="这是啥" City=BeiJing Countey=China animals=dogtime="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)

这样就会将哪个文件哪一行 都记录下来  但是不是特殊需求无需开启这个 因为会增加性能开

关于使用Golang怎么操作数据库问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网行业资讯频道了解更多相关知识。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯