美文网首页Go入门系列
Go入门系列(七)数据库

Go入门系列(七)数据库

作者: RabbitMask | 来源:发表于2020-03-16 18:33 被阅读0次

    目录:
    一、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相关学习。

    相关文章

      网友评论

        本文标题:Go入门系列(七)数据库

        本文链接:https://www.haomeiwen.com/subject/xykbshtx.html