Go入门系列

Go入门系列(七)数据库

2020-03-16  本文已影响0人  RabbitMask

目录:
一、MySQL
二、Redis

本章节我们选取了关系型数据库的代表MySQL和NoSQL的代表Redis为例。

一、MySQL

对MySQL的操作用到了第三方包github.com/go-sql-driver/mysql,我本地随便找了个dvwa的库作为演示,首先是数据库连接和查询功能,查询当前库中user表,预设了两个用户:

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

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/dvwa?charset=utf8")
    if err!=nil {
        fmt.Println(err.Error())
        return
    }

    rows, err := db.Query("select *from user ")
    var user string
    var password string
    if err!=nil {
        fmt.Println(err.Error())
        return
    }
    for rows.Next()  {
        rows.Scan(&user,&password)
        fmt.Println(user,password)
    }
}
#输出
rabbit rabbit
carrot carrot

这里顺便插一句,上面的代码虽然实现了功能,但是我们没有考虑到查询结果为空的情况,我们顺便对错误处理进行一下优化:

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/dvwa?charset=utf8")
    checkErr(err)

    rows, err := db.Query("select *from user ")
    var user string
    var password string
    checkErr(err)
    for rows.Next()  {
        err=rows.Scan(&user,&password)
        checkErr(err)
        fmt.Println(user,password)
    }
}

func checkErr(err error) {
    if err != nil {
        fmt.Println(err.Error())
        return
    }
}

然后尝试进行单条查询:

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/dvwa?charset=utf8")
    checkErr(err)
    var user string
    var password string
    err=db.QueryRow("select * from user where user=?","rabbit").Scan(&user,&password)
    checkErr(err)
    fmt.Println(user,password)
}
#输出
rabbit rabbit

然后是新增用户,即数据插入操作。因为要用到主键,重新设计了下user表,其中用到的LastInsertId()方法从字面上应该也好理解,最新插入的数据id。

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/dvwa?charset=utf8")
    checkErr(err)

    sqlStr := "insert into user(user, password) values (?,?)"
    res,err := db.Exec(sqlStr, "rabbitmask", "123456")
    checkErr(err)
    newid,err:=res.LastInsertId()
    checkErr(err)
    fmt.Println("插入成功,新增ID为:",newid)
}
#输出
插入成功,新增ID为: 4

这里再补充一点,之前在python代码审计的文章中我提到过为了避免SQL注入大家可以尽可能多的使用参数化查询,其实上面的数据插入样例就是参数化查询。然而Go语言提供了预处理功能,安全性更高。

普通SQL语句执行过程:

客户端对SQL语句进行占位符替换得到完整的SQL语句。
客户端发送完整SQL语句到MySQL服务端
MySQL服务端执行完整的SQL语句并将结果返回给客户端。

预处理执行过程:

把SQL语句分成两部分,命令部分与数据部分。
先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理。
然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换。
MySQL服务端执行完整的SQL语句并将结果返回给客户端。

Go语言中使用Prepare方法会先将sql语句发送给MySQL服务端,返回一个准备好的状态用于之后的查询和命令,返回值可以同时执行多个查询和命令。

我们接下来以数据更新为例加入预处理功能:

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/dvwa?charset=utf8")
    checkErr(err)
    sqlStr := "update user set password = ? where user = ?"
    stmt, err := db.Prepare(sqlStr)
    checkErr(err)
    defer stmt.Close()
    res,err := stmt.Exec("666666", "rabbitmask")
    checkErr(err)
    setid,err:=res.RowsAffected()
    checkErr(err)
    fmt.Println("影响的行数为:",setid)
}
#输出
影响的行数为: 1

最后!删除操作:

func main() {
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/dvwa?charset=utf8")
    checkErr(err)
    sqlStr := "delete from user where user = ?"
    stmt, err := db.Prepare(sqlStr)
    checkErr(err)
    res,err := stmt.Exec("rabbitmask")
    checkErr(err)
    setid,err:=res.RowsAffected()
    checkErr(err)
    fmt.Println("影响的行数为:",setid)
}
#输出
影响的行数为: 1

二、Redis

关于其第三方包的选择GitHub给的排行很清晰:github.com/gomodule/redigo
首先拉起redis服务后,对服务器进行连接:

import (
    "fmt"
    "github.com/gomodule/redigo/redis"
)

func main()  {
    conn,err := redis.Dial("tcp","127.0.0.1:6379")
    checkErr(err)
    fmt.Println("Redis 连接成功")
    defer conn.Close()
}

func checkErr(err error) {
    if err != nil {
        fmt.Println(err.Error())
        return
    }
}
#输出
Redis 连接成功

然后尝试执行redis set/get命令:

func main()  {
    conn,err := redis.Dial("tcp","127.0.0.1:6379")
    checkErr(err)
    fmt.Println("Redis 连接成功")
    defer conn.Close()

    _, err = conn.Do("SET", "name", "rabbitmask","EX","600")
    checkErr(err)
    name, err := redis.String(conn.Do("GET", "name"))
    checkErr(err)
    fmt.Println(name)
}
#输出
Redis 连接成功
rabbitmask

再或者你想用到渗透工作中,执行redis系统命令:

func main()  {
    conn,err := redis.Dial("tcp","127.0.0.1:6379")
    checkErr(err)
    fmt.Println("Redis 连接成功")
    defer conn.Close()

    info, err := redis.String(conn.Do("info", "Replication"))
    checkErr(err)
    fmt.Println(info)
}
#输出
Redis 连接成功
# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

没有太多可拓展的,更多的操作参见redis相关学习。

上一篇下一篇

猜你喜欢

热点阅读