Go语言中mysql数据库操作(一)

数据的持久化是程序中必不可少的,所以编程语言中对数据库的操作是非常重要的一块,本文介绍Go语言对mysql数据库的操作。

基本操作

建立连接

db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")
errDeal("连接数据库", err)
defer db.Close()

连接参数一般有以下几种

user@unix(/path/to/socket)/dbname?charset=utf8
user:password@tcp(localhost:5555)/dbname?charset=utf8
user:password@/dbname
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname

增删改操作

// 插入数据---------------------方法1
result, err := db.Exec("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +
" VALUES(?,now(),?,?,?)", "admin", "127.0.0.1", "登录", "登录成功")
errDeal("插入数据", err)
// 查看返回信息
count, err := result.RowsAffected()
errDeal("查看插入数据条数", err)
fmt.Printf("插入数据条数:%d\n", count)
id, err := result.LastInsertId()
errDeal("查看最后插入数据的id", err)
fmt.Printf("最后插入数据的id:%d\n", id)

// 插入数据---------------------方法2,先创建一个预处理语句,再执行
stmt, err := db.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +
" VALUES(?,now(),?,?,?)")
result1, err1 := stmt.Exec("admin", "127.0.0.1", "登录", "登录成功")
errDeal("方法2插入数据", err1)
fmt.Println(result1.LastInsertId())

// 删除数据
result2, err := db.Exec("DELETE FROM admin_log WHERE id=?", 2014)
fmt.Println(result2.RowsAffected())

// 更新数据
result3, err := db.Exec("UPDATE admin_log SET log_ip=? WHERE id=?", "192.168.8.9", 2017)
fmt.Println(result3.RowsAffected())

单条数据查询

// 先定义存储查询结果的变量
var rid int
var username, time, ip, logType string
var desc, remark, spare interface{} // 如果字段中可能出现值为nil的情况,可以将变量申明为interface{}类型
err2 := db.QueryRow("SELECT id,admin_username,log_time,log_ip,log_type,log_desc,remark,spare" +
    " FROM admin_log WHERE id=?", 2017).Scan(&rid, &username, &time, &ip, &logType, &desc, &remark, &spare) // 传入的是变量的指针
errDeal("查询单条数据", err2)
fmt.Printf("id=%d,username=%s,time=%s,ip=%s,logType=%s,desc=%s,remark=%v,spare=%v\n", rid, username, time, ip, logType, desc, remark, spare)

多条数据查询

// 查询多条数据
rows, err3 := db.Query("SELECT admin_username,log_time,log_ip,log_type,log_desc" +
    " FROM admin_log WHERE id=? OR id=?", 2017, 2019)
errDeal("查询多条数据", err3)
// 对多条数据进行遍历
for rows.Next() {
    err4 := rows.Scan(&username, &time, &ip, &logType, &desc)
    errDeal("遍历多条数据", err4)
    fmt.Printf("username=%s,time=%s,ip=%s,logType=%s,desc=%s\n", username, time, ip, logType, desc)
}

// 如果查询中不指定具体字段,使用*
rows, err33 := db.Query("SELECT *" +
    " FROM admin_log WHERE id>?", 2017)
errDeal("查询多条数据", err33)
// 查询所有字段名,返回string切片
columes, err333 := rows.Columns()
errDeal("rows.Columns()方法调用", err333)
fmt.Printf("%T----%v\n", columes, columes)
var scanColumes = make([]interface{}, len(columes))
var values = make([]interface{}, len(columes))
for index, _ := range  scanColumes {
    scanColumes[index] = &values[index]
}
for rows.Next() {
    err4 := rows.Scan(scanColumes...)
    errDeal("遍历多条数据", err4)
    for i, val := range values {
        if strings.EqualFold(judgeType(val), "[]uint8") {
            fmt.Printf("%s(%T)==%s\t", columes[i], val, val)
        } else {
            fmt.Printf("%s(%T)==%v\t", columes[i], val, val)
        }

    }
    fmt.Println()
}

事务

开启事务

// 开启事务,tx是从连接池中取出一个连接,在关闭之前都是使用这个连接,提交事务和回滚事务都是操作tx
tx, err5 := db.Begin()
errDeal("开启事务", err5)
_, err6 := tx.Exec("UPDATE admin_log SET log_desc=? WHERE id=?", "测试事务222", 2019)
//if err6 != nil {
if err6 == nil {
    tx.Rollback() // 回滚
}
tx.Commit() // 提交

批量插入数据

// 批量数据插入
tx, err7 := db.Begin()
errDeal("数据批量插入,开启事务", err7)
insertValues := [][]interface{}{{"admin", "127.0.0.1", "登录", "登录成功"},{"admin", "127.0.0.1", "删除", "删除数据"},{"admin", "127.0.0.1", "退出", "退出系统"}}
stmt, err8 := tx.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")
errDeal("数据批量插入,预处理", err8)
for _, val := range  insertValues {
    _, err := stmt.Exec(val...)
    if err != nil {
        fmt.Printf("出现错误回滚,错误信息:%v", err)
        tx.Rollback()
    }
}
tx.Commit()

sqlx的使用及批量插入

xdb, err9 := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")
errDeal("sqlx连接数据库", err9)
txx, err10 := xdb.Beginx()
errDeal("sqlx开启事务", err10)
insertValuesx := [][]interface{}{{"admin", "127.0.0.1", "登录", "登录成功X"},{"admin", "127.0.0.1", "删除", "删除数据X"},{"admin", "127.0.0.1", "退出", "退出系统X"}}
stmtx, err11 := txx.Preparex("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")
errDeal("数据批量插入,预处理", err11)
for _, val := range insertValuesx {
    _, err := stmtx.Exec(val...)
    if err != nil {
        fmt.Printf("sqlx出现错误回滚,错误信息:%v", err)
        txx.Rollback()
    }
}
txx.Commit()

完整代码

package main

import (
    "database/sql"
    _"github.com/go-sql-driver/mysql" // 这里很重要,导入自己本地使用的数据库驱动,前面是下划线,否则会报错:sql: unknown driver "mysql" (forgotten import?)
    "fmt"
    "strings"
    "github.com/jmoiron/sqlx"
)

func main() {
    // 连接数据库,用户名:密码@协议(地址:端口)/数据库?参数=参数值,常用"用户名:密码@tcp(ip:端口)/数据库名?charset=字符集"
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")
    errDeal("连接数据库", err)
    defer db.Close()

    //=========================================================================================增删改
    // 插入数据---------------------方法1
    result, err := db.Exec("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +
        " VALUES(?,now(),?,?,?)", "admin", "127.0.0.1", "登录", "登录成功")
    errDeal("插入数据", err)
    // 查看返回信息
    count, err := result.RowsAffected()
    errDeal("查看插入数据条数", err)
    fmt.Printf("插入数据条数:%d\n", count)
    id, err := result.LastInsertId()
    errDeal("查看最后插入数据的id", err)
    fmt.Printf("最后插入数据的id:%d\n", id)

    // 插入数据---------------------方法2,先创建一个预处理语句,再执行
    stmt, err := db.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc)" +
        " VALUES(?,now(),?,?,?)")
    result1, err1 := stmt.Exec("admin", "127.0.0.1", "登录", "登录成功")
    errDeal("方法2插入数据", err1)
    fmt.Println(result1.LastInsertId())

    // 删除数据
    result2, err := db.Exec("DELETE FROM admin_log WHERE id=?", 2014)
    fmt.Println(result2.RowsAffected())

    // 更新数据
    result3, err := db.Exec("UPDATE admin_log SET log_ip=? WHERE id=?", "192.168.8.9", 2017)
    fmt.Println(result3.RowsAffected())

    //=============================================================================================查询
    // 查询单条数据
    // 先定义存储查询结果的变量
    var rid int
    var username, time, ip, logType string
    var desc, remark, spare interface{} // 如果字段中可能出现值为nil的情况,可以将变量申明为interface{}类型
    err2 := db.QueryRow("SELECT id,admin_username,log_time,log_ip,log_type,log_desc,remark,spare" +
        " FROM admin_log WHERE id=?", 2017).Scan(&rid, &username, &time, &ip, &logType, &desc, &remark, &spare) // 传入的是变量的指针
    errDeal("查询单条数据", err2)
    fmt.Printf("id=%d,username=%s,time=%s,ip=%s,logType=%s,desc=%s,remark=%v,spare=%v\n", rid, username, time, ip, logType, desc, remark, spare)

    // 查询多条数据
    rows, err3 := db.Query("SELECT admin_username,log_time,log_ip,log_type,log_desc" +
        " FROM admin_log WHERE id=? OR id=?", 2017, 2019)
    errDeal("查询多条数据", err3)
    // 对多条数据进行遍历
    for rows.Next() {
        err4 := rows.Scan(&username, &time, &ip, &logType, &desc)
        errDeal("遍历多条数据", err4)
        fmt.Printf("username=%s,time=%s,ip=%s,logType=%s,desc=%s\n", username, time, ip, logType, desc)
    }

    // 如果查询中不指定具体字段,使用*
    rows, err33 := db.Query("SELECT *" +
        " FROM admin_log WHERE id>?", 2017)
    errDeal("查询多条数据", err33)
    // 查询所有字段名,返回string切片
    columes, err333 := rows.Columns()
    errDeal("rows.Columns()方法调用", err333)
    fmt.Printf("%T----%v\n", columes, columes)
    var scanColumes = make([]interface{}, len(columes))
    var values = make([]interface{}, len(columes))
    for index, _ := range  scanColumes {
        scanColumes[index] = &values[index]
    }
    for rows.Next() {
        err4 := rows.Scan(scanColumes...)
        errDeal("遍历多条数据", err4)
        for i, val := range values {
            if strings.EqualFold(checkType(val), "[]uint8") {
                fmt.Printf("%s(%T)==%s\t", columes[i], val, val)
            } else {
                fmt.Printf("%s(%T)==%v\t", columes[i], val, val)
            }

        }
        fmt.Println()
    }

    // ==================================================================================================事务
    // 开启事务,tx是从连接池中取出一个连接,在关闭之前都是使用这个连接,提交事务和回滚事务都是操作tx
    tx, err5 := db.Begin()
    errDeal("开启事务", err5)
    _, err6 := tx.Exec("UPDATE admin_log SET log_desc=? WHERE id=?", "测试事务222", 2019)
    //if err6 != nil {
    if err6 == nil {
        tx.Rollback() // 回滚
    }
    tx.Commit() // 提交

    // 批量数据插入
    tx, err7 := db.Begin()
    errDeal("数据批量插入,开启事务", err7)
    insertValues := [][]interface{}{{"admin", "127.0.0.1", "登录", "登录成功"},{"admin", "127.0.0.1", "删除", "删除数据"},{"admin", "127.0.0.1", "退出", "退出系统"}}
    stmt, err8 := tx.Prepare("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")
    errDeal("数据批量插入,预处理", err8)
    defer stmt.Close()
    // 通过循环将每条SQL的参数写到目标表缓冲区。
    for _, val := range  insertValues {
        _, err := stmt.Exec(val...)
        if err != nil {
            fmt.Printf("出现错误回滚,错误信息:%v", err)
            tx.Rollback()
        }
    }
    tx.Commit()

    // 使用sqlx批量数据插入
    xdb, err9 := sqlx.Open("mysql", "root:root@tcp(127.0.0.1:3306)/betting?charset=utf8")
    errDeal("sqlx连接数据库", err9)
    defer xdb.close()
    txx, err10 := xdb.Beginx()
    errDeal("sqlx开启事务", err10)
    insertValuesx := [][]interface{}{{"admin", "127.0.0.1", "登录", "登录成功X"},{"admin", "127.0.0.1", "删除", "删除数据X"},{"admin", "127.0.0.1", "退出", "退出系统X"}}
    stmtx, err11 := txx.Preparex("INSERT INTO admin_log(admin_username,log_time,log_ip,log_type,log_desc) VALUES(?,now(),?,?,?)")
    errDeal("数据批量插入,预处理", err11)
    defer stmtx.Close()
    // 通过循环将每条SQL的参数写到目标表缓冲区。
    for _, val := range insertValuesx {
        _, err := stmtx.Exec(val...)
        if err != nil {
            fmt.Printf("sqlx出现错误回滚,错误信息:%v", err)
            txx.Rollback()
        }
    }
    txx.Commit()
}

func errDeal(info string, err error) {
    if err != nil {
        panic(fmt.Sprintf("%s,错误信息:%v", info, err))
    }
}

func checkType(val interface{}) string {
    switch val.(type) {
    case []uint8 :
        return "[]uint8"
    }
    return ""
}

原创文章,作者:RJPOM,如若转载,请注明出处:https://www.beidanyezhu.com/a/26234.html

(0)
RJPOM的头像RJPOM
上一篇 2025-01-01 17:24:58
下一篇 2025-01-01

相关推荐

  • go语言使用json隐藏字段的方法

    使用场景:在 go 中给 API 调用者响应 json 数据。 1. 有些字段不暴露给用户。 2. 有些字段是根据用户的级别控制是否有这些数据。 Id字段不暴露给用户,则使用 `j…

    2025-01-03
  • go语言中可以把包名去掉吗

    Golang不可以把包名去掉,包名是一种类似命名空间的管理和组织代码的方式,而Golang的包有两种类型,一种是“main”包,该包的可以有唯一的一个“main”函数,这个函数也是…

  • go语言支持泛型吗

    Golang团队认为在类型系统和运行时的复杂性花费太大,还没找到可以和这个复杂性相抵的良好设计。 内置的map和slice其实都有泛型的味道,加上可以用interface{}来构造…

  • go语言适合开发web吗

    go语言适合开发web吗?相信大部分人都不太了解,今天小编为了让大家更加了解,给大家总结了以下内容,跟随小编一起来看看吧。 网络编程方面,Go语言广泛应用于 Web 应用、API …

  • go语言中的反射

    反射是什么? 反射是一种计算机处理方式。有程序可以访问、检测和修改它本身状态或行为的这种能力。能提供封装程序集、类型的对象。(程序集包含模块,而模块包含类型,类型又包含成员。)Go…

  • go语言中的byte是什么

    字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。 Go语言的字符有以下两种: 一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的…

  • go语言适合开发什么

    其实Go语言主要用作服务器端开发,其定位是用来开发“大型软件”的,适合于需要很多程序员一起开发,并且开发周期较长的大型软件和支持云计算的网络服务。 Go语言融合了传统编译型语言的高…

  • go语言中的nil是什么

    大家都清楚,当你声明了一个变量 但却还并木优赋值时,golang中会自动给你的变量类型给一个对应的默认零值。 这是每种类型对应的零值: bool -> false numbe…

  • 如何设计go语言中的log

    Go语言是谷歌2009发布的第二款开源编程语言。Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。 …

  • go语言中make和new的区别是什么

    make、new make用于内建类型(map、slice 和channel)的内存分配,golang分配内存有一个make函数,该函数第一个参数是类型,第二个参数是分配的空间,第…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

分享本页
返回顶部