zoukankan      html  css  js  c++  java
  • GO数据库

    Golang 数据库操作


    Golang 数据库 MySQL


    Golang支持DB操作位于database包下,支持基本CRUD操作、事务和Prepared Statement,本文以MySQL为例。


    MySQL驱动安装 
    使用数据库之前,必须安装相关MySQL数据驱动[1],如果未安装驱动或者没有引入驱动库会报以下错误: 
    failed to open database: sql: unknown driver "mysql" (forgotten import?) 
    安装golang mysql driver 
    go get github.com/go-sql-driver/mysql 
    代码中还需注册数据库驱动,通过引入空白倒入[2]mysql包来完成


    import(
    "database/sql"
    // 引入数据库驱动注册及初始化
    _ "github.com/go-sql-driver/mysql" ) 
    这段空白倒入代码实际执行mysql包的初始化代码,位于%GOPATH%/github.com/go-sql-driver/mysql/driver.go


    func init() {
        sql.Register("mysql", &MySQLDriver{})
    }
    准备测试数据 
    连接MySQL 
    mysql -uroot -p 
    选择数据库test 
    use test 
    创建测试用的users表和order表,并插入测试数据


    #创建user表
    DROP TABLE IF EXISTS `order`;
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE IF NOT EXISTS `user` (`uid` SERIAL PRIMARY KEY, `name` VARCHAR(20) NOT NULL, `password` VARCHAR(20) NOT NULL) ENGINE=`innodb`, CHARACTER SET=utf8;
    #创建order表
    CREATE TABLE IF NOT EXISTS `order`(`oid` SERIAL PRIMARY KEY, `uid`  BIGINT(20) UNSIGNED NOT NULL, `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (`uid`) REFERENCES `user`(`uid`))ENGINE=innodb,CHARACTER SET=utf8;
    #插入测试数据
    INSERT INTO  `user`(`name`,`password`) VALUES('nick', 'nick'),('jacky', 'jacky');
    INSERT INTO `order`(`uid`) VALUES(1),(2);
    连接数据库 
    连接数据的DSN格式为: 
    username:password@protocol(address)/dbname?param=value 
    示例代码:


    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test?charset=utf8")
        if err != nil {
            fmt.Println("failed to open database:", err.Error())
            return
        }
        if err := db.Ping(); err != nil {
            fmt.Println("%s error ping database: %s", err.Error())
            return
        }
        defer db.Close()
    返回的DB对象,实际封装了一个数据库连接池,对于goroutine是线程安全的,可以放心使用。这个数据库连接池由"database/sql"包负责自动创建和回收。连接池的大小可以由SetMaxIdleConns指定。 
    需要注意的是,创建DB对象成功,并不代表已经成功的连接了数据库,数据库连接只有在真正需要的时候才会被创建。因此如果,在创建DB对象后想验证数据库连接是否有效,可以调用Ping()或者通过


    关闭数据库


    defer db.Close()
    关闭数据库并释放全部已打开的资源。实际上,很少需要进行关闭操作,DB对象实际上长期存活并在所有的goroutine之间共享


    CRUD 
    DB中执行SQL通过Exec和Query方法,查询操作是通过Query完成,它会返回一个sql.Rows的结果集,包含一个游标用来遍历查询结果;Exec方法返回的是sql.Result对象,用于检测操作结果,及被影响记录数


    查询


    // 获取USERS表中的前十行记录
    rows, err := db.Query("SELECT * FROM user")
    if err != nil {
        fmt.Println("fetech data failed:", err.Error())
        return
    }
    defer rows.Close()
    for rows.Next() {
        var uid int
        var name, password string
        rows.Scan(&uid, &name, &password)
        fmt.Println("uid:", uid, "name:", name, "password:", password)
    }
    注意:rows必须进行关闭否则会导致数据库连接无法关闭,长时间运行会导致"too many connections" 
    插入


    // 插入一条新数据
    result, err := db.Exec("INSERT INTO `user`(`name`,`password`) VALUES('tom', 'tom')")
    if err != nil {
        fmt.Println("insert data failed:", err.Error())
        return
    }
    id, err := result.LastInsertId()
    if err != nil {
        fmt.Println("fetch last insert id failed:", err.Error())
        return
    }
    fmt.Println("insert new record", id)
    更新


    // 更新一条数据
    result, err = db.Exec("UPDATE `user` SET `password`=? WHERE `name`=?", "tom_new_password", "tom")
    if err != nil {
        fmt.Println("update data failed:", err.Error())
        return
    }
    num, err := result.RowsAffected()
    if err != nil {
        fmt.Println("fetch row affected failed:", err.Error())
        return
    }
    fmt.Println("update recors number", num)
    删除


    // 删除数据
    result, err = db.Exec("DELETE FROM `user` WHERE `name`=?", "tom")
    if err != nil {
        fmt.Println("delete data failed:", err.Error())
        return
    }
    num, err = result.RowsAffected()
    if err != nil {
        fmt.Println("fetch row affected failed:", err.Error())
        return
    }
    fmt.Println("delete record number", num)
    事务支持 
    sql.Tx用来支持事务处理


    // 事务处理
    // 完全删除用户编号为2的用户数据
    tx, err := db.Begin()
    result, err = tx.Exec("DELETE FROM `order` WHERE uid=? ", 2)
    if err != nil {
        fmt.Println("delete data failed:", err.Error())
        return
    }
    num, err = result.RowsAffected()
    if err != nil {
        fmt.Println("fetch row affected failed:", err.Error())
        return
    }
    fmt.Println("delete record number", num)
    result, err = tx.Exec("DELETE FROM `user` WHERE uid=? ", 2)
    if err != nil {
        fmt.Println("delete data failed:", err.Error())
        return
    }
    num, err = result.RowsAffected()
    if err != nil {
        fmt.Println("fetch row affected failed:", err.Error())
        return
    }
    fmt.Println("delete record number", num)
    // 根据条件回滚或者提交
    // tx.Rollback()
    tx.Commit()
    Prepared Statement 
    sql.Stmt支持预备表达式,可以用来优化SQL查询提高性能,减少SQL注入的风险, DB.Prepare()和Tx.Prepare()都提供了对于预备表达式的支持。


    // 预备表达式
    stmt, err := db.Prepare("DELETE FROM `order` WHERE `oid`=?")
    if err != nil {
        fmt.Println("fetch row affected failed:", err.Error())
        return
    }
    result, err = stmt.Exec(1)
    if err != nil {
        fmt.Println("delete data failed:", err.Error())
        return
    }
    num, err = result.RowsAffected()
    if err != nil {
        fmt.Println("fetch row affected failed:", err.Error())
        return
    }
    fmt.Println("delete record number", num)

  • 相关阅读:
    tcpip数据包编码解析(chunk and gzip)_space of Jialy_百度空间
    epoll 事件之 EPOLLRDHUP
    c What is the Difference Between read() and recv() , and Between send() and write()? Stack Overflow
    HTTP KeepAlive详解 IT心雪的日志 网易博客
    北京生活 TIPS 银行服务篇
    eventfdaiotest.c
    北京生活 TIPS 谈谈日常理财
    C语言抓http gzip包并解压 失败 C/C++ ChinaUnix.net
    转:javascript 对象和原型
    转:Javascript原型链和原型的一个误区
  • 原文地址:https://www.cnblogs.com/zhangym/p/5583431.html
Copyright © 2011-2022 走看看