醉翁之意 發表於 2020-2-27 19:30:00

Go Mysql驱动

<p class="p2"><strong>Golang中MYSQL驱动</strong></p>
<ul>
<li class="p2">Mysql库https://github.com/go-sql-driver/mysql</li>
<li class="p2">Go本身不提供具体数据库驱动,只提供驱动接口和管理。</li>
<li class="p2">各个数据库驱动需要第三方实现,并且注册到Go中的驱动管理中。</li>
</ul>
<p>&nbsp;</p>
<p><strong>安装golang mysql drvier</strong></p>
<p>go get github.com/go-sql-driver/mysql</p>
<p>代码中需要注册mysql数据库驱动,通过引入空白导入mysql包来完成。</p>
<p>为什么需要使用空白导入? 是因为需要执行mysql包的初始化代码(代码位于%GOPATH%/github.com/go-sql-driver/mysql/driver.go)</p>
<div class="cnblogs_code">
<pre>func init() {
    sql.Register("mysql", &amp;MySQLDriver{})
}</pre>
</div>
<p>&nbsp;</p>
<p><strong>连接数据的DSN格式</strong></p>
<p><code>username:password@protocol(address)/dbname?param=value</code></p>
<p>&nbsp;</p>
<p><strong>Prepared Statement</strong>&nbsp;<br>sql.Stmt支持预备表达式,可以用来优化SQL查询提高性能,减少SQL注入的风险, DB.Prepare()和Tx.Prepare()都提供了对于预备表达式的支持。</p>
<p><strong>预处理的流程:</strong><br>step1. 将sql分为2部分.命令部分和数据部分.<br>step2. 首先将命令部分发送给mysql服务器,mysql进行预处理.(如生成AST)<br>step3. 然后将数据部分发送给mysql服务器,mysql进行占位符替换.<br>step4. mysql服务器执行sql语句,把执行结果发送给客户端.</p>
<p><strong>预处理的优势:</strong><br>1.因为发送命令后,在mysql服务器端,就会将AST生成好,所以不需要对每一次值的更换都重新生成一次AST.对同样的数据不同的SQL来讲,只需生成1次AST,并缓存起来即可.<br>2.避免SQL注入.因为mysql知道再次发送过来的内容为”数据”,因此不会将这些数据解析为SQL,避免了SQL注入.</p>
<p><strong>需要注意的点:</strong><br>使用预处理进行查询操作时,不仅在defer时需要关闭结果集,而且还要关闭命令句柄,否则同样会占用连接,导致阻塞.</p>
<div class="cnblogs_code">
<p>package main</p>
<p>import (<br>    "database/sql"<br>    _ "github.com/go-sql-driver/mysql"<br>    "fmt"<br>)</p>
<p>type User struct {<br>    Id int `db:"id"`<br>    Name string `db:"name"`<br>    Age int `db:"age"`<br>}</p>
<p><br>func PrepareQuery(db *sql.DB, id int) {<br>    stmt, err := db.Prepare("select id, name, age from user where id&gt;?")<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    rows, err := stmt.Query(id)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    defer stmt.Close()<br>    defer rows.Close()</p>
<p>    for rows.Next(){<br>      var user User<br>      err := rows.Scan(&amp;user.Id, &amp;user.Name, &amp;user.Age)<br>      if err != nil {<br>            panic(err)<br>      }<br>      fmt.Printf("user: %#v\n", user)<br>    }<br>}</p>
<p>func main() {</p>
<p>    dns := "root:123456@tcp(172.16.65.200:3306)/golang"<br>    db, err := sql.Open("mysql", dns)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    defer db.Close()</p>
<p>    PrepareQuery(db, 0)</p>
<p>}</p>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong>Mysql创建表:</strong></p>
<p>  CREATE TABLE user (</p>
<p>  id int(20) NOT NULL AUTO_INCREMENT,</p>
<p>  name varchar(20) DEFAULT '',</p>
<p>  age int(2) DEFAULT '0',</p>
<p>  PRIMARY KEY (id))</p>
<p>  ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT&nbsp; CHARSET=utf8mb4;</p>
<p>&nbsp;</p>
<p>数据库增删改查</p>
<p>insert</p>
<div class="cnblogs_code">
<p>package main</p>
<p>import (<br>    "database/sql"<br>    _ "github.com/go-sql-driver/mysql"<br>    "fmt"<br>)</p>
<p>func Insert(db *sql.DB) {<br>    name := "Vincent"<br>    age := 18</p>
<p>    result, err := db.Exec("insert into user(name, age) values (?,?)", name, age)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    id, err := result.LastInsertId()<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    affected, err := result.RowsAffected()<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    fmt.Printf("last insert id:%d affect rows:%d\n", id, affected)<br>}</p>
<p>func main() {<br>    dns := "root:123456@tcp(172.16.65.200:3306)/golang"<br>    db, err := sql.Open("mysql", dns)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    err = db.Ping()<br>    if err != nil {<br>      panic(err)<br>    }<br>    fmt.Println("connect to db success!!!")<br>    Insert(db)<br>}</p>
<br>
<div id="cnblogs_code_open_46ed7098-2547-4d5f-ad3f-5ac0a66c8bdd" class="cnblogs_code_hide">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
<pre>package main

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

func Insert(db *sql.DB) {
    name := "Vincent"
    age := 18

    result, err := db.Exec("insert into user(name, age) values (?,?)", name, age)
    if err != nil {
      panic(err)
    }

    id, err := result.LastInsertId()
    if err != nil {
      panic(err)
    }

    affected, err := result.RowsAffected()
    if err != nil {
      panic(err)
    }

    fmt.Printf("last insert id:%d affect rows:%d\n", id, affected)
}

func main() {
    dns := "root:123456@tcp(172.16.65.200:3306)/golang"
    db, err := sql.Open("mysql", dns)
    if err != nil {
      panic(err)
    }

    err = db.Ping()
    if err != nil {
      panic(err)
    }
    fmt.Println("connect to db success!!!")
    Insert(db)
}</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
</div>
</div>
<p>delete</p>
<div class="cnblogs_code">
<p>package main</p>
<p>import (<br>    "database/sql"<br>    _ "github.com/go-sql-driver/mysql"<br>    "fmt"<br>)</p>
<p>func Delete(db *sql.DB, id int) {<br>    result, err := db.Exec("delete from user where id=?", id)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    rowsAffected, err := result.RowsAffected()<br>    if err != nil {<br>      panic(err)<br>    }<br>    fmt.Printf("delect id:%d, affect rows:%d\n", id, rowsAffected)<br>}</p>
<p>func main() {<br>    dns := "root:123456@tcp(172.16.65.200:3306)/golang"<br>    db, _ := sql.Open("mysql", dns)<br>    Delete(db, 2)<br>}</p>
<br>
<div id="cnblogs_code_open_b1d87df4-94f6-441d-a601-bd212f80b19b" class="cnblogs_code_hide">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
<pre>package main

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

func Delete(db *sql.DB, id int) {
    result, err := db.Exec("delete from user where id=?", id)
    if err != nil {
      panic(err)
    }

    rowsAffected, err := result.RowsAffected()
    if err != nil {
      panic(err)
    }
    fmt.Printf("delect id:%d, affect rows:%d\n", id, rowsAffected)
}

func main() {
    dns := "root:123456@tcp(172.16.65.200:3306)/golang"
    db, _ := sql.Open("mysql", dns)
    Delete(db, 2)
}</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
</div>
</div>
<p>update</p>
<div class="cnblogs_code">
<p>package main</p>
<p>import (<br>    "database/sql"<br>    _ "github.com/go-sql-driver/mysql"<br>    "fmt"<br>)</p>
<p>func Update(db *sql.DB) {<br>    name := "Miles"<br>    age := 88<br>    id := 3</p>
<p>    result, err := db.Exec("update user set name=?, age=? where id=?", name, age, id)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    // RowsAffected returns the number of rows affected by an<br>    // update, insert, or delete.<br>    rowsAffected, err := result.RowsAffected()<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    fmt.Printf("update id:%d, affect rows:%d\n", id, rowsAffected)</p>
<p>}</p>
<p>func main() {<br>    dns := "root:123456@tcp(172.16.65.200:3306)/golang"<br>    db, err := sql.Open("mysql", dns)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    err = db.Ping()<br>    if err != nil {<br>      panic(err)<br>    }<br>    fmt.Println("connect to db success!!!")<br>    Update(db)<br>}</p>
<br>
<div id="cnblogs_code_open_214abfe6-6b22-4963-ab28-704e96f487cb" class="cnblogs_code_hide">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
<pre>package main

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

func Update(db *sql.DB) {
    name := "Miles"
    age := 88
    id := 3

    result, err := db.Exec("update user set name=?, age=? where id=?", name, age, id)
    if err != nil {
      panic(err)
    }

    // RowsAffected returns the number of rows affected by an
    // update, insert, or delete.
    rowsAffected, err := result.RowsAffected()
    if err != nil {
      panic(err)
    }

    fmt.Printf("update id:%d, affect rows:%d\n", id, rowsAffected)

}

func main() {
    dns := "root:123456@tcp(172.16.65.200:3306)/golang"
    db, err := sql.Open("mysql", dns)
    if err != nil {
      panic(err)
    }

    err = db.Ping()
    if err != nil {
      panic(err)
    }
    fmt.Println("connect to db success!!!")
    Update(db)
}</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
</div>
</div>
<p>query</p>
<div class="cnblogs_code">
<p>package main</p>
<p>import (<br>    "database/sql"<br>    _ "github.com/go-sql-driver/mysql"<br>    "fmt"<br>    "log"<br>)</p>
<p>type User struct {<br>    Id int `db:"id"`<br>    Name string `db:"name"`<br>    Age int `db:"age"`<br>}</p>
<p>&nbsp;</p>
<p>// 单行查询,如果查询到多个结果,只返回第一行,查询不到结果就ErrNoRows错误。<br>func QueryRow(db *sql.DB) {<br>    id:= 2<br>    row := db.QueryRow("select id, name, age from user where id=?", id)</p>
<p>    var user User<br>    err := row.Scan(&amp;user.Id, &amp;user.Name, &amp;user.Age)</p>
<p>    if err == sql.ErrNoRows {<br>      log.Printf("not found data of the id:%d",id)<br>    }</p>
<p>    if err != nil {<br>      panic(err)<br>    }</p>
<p><br>    fmt.Printf("user: %#v\n", user)<br>}</p>
<p><br>// 多行查询, 查询不到任何记录也不会报错。<br>func Query(db *sql.DB) {<br>    id := 0<br>    rows, err := db.Query("select id, name, age from user where id&gt;?", id)<br>    if err != nil {<br>      panic(err)<br>    }<br>    if err == sql.ErrNoRows {<br>      log.Printf("not found data of id:%d\n", id)<br>      return<br>    }<br>    defer rows.Close()</p>
<p>    for rows.Next() {<br>      var user User<br>      err := rows.Scan(&amp;user.Id, &amp;user.Name, &amp;user.Age)<br>      if err != nil {<br>            panic(err)<br>      }<br>      fmt.Printf("user: %#v\n", user)<br>    }</p>
<p>}</p>
<p>func main() {<br>    dns := "root:123456@tcp(172.16.65.200:3306)/golang"<br>    db, err := sql.Open("mysql", dns)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    err = db.Ping()<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    fmt.Printf("connect to db success\n")</p>
<p>    //QueryRow(db)</p>
<p>    Query(db)<br>}</p>
<br>
<div id="cnblogs_code_open_70b268d6-3efd-4a4a-9c26-ba84d6a1c7b9" class="cnblogs_code_hide">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
<pre>package main

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

type User struct {
    Id int `db:"id"`
    Name string `db:"name"`
    Age int `db:"age"`
}



// 单行查询,如果查询到多个结果,只返回第一行,查询不到结果就ErrNoRows错误。
func QueryRow(db *sql.DB) {
    id:= 2
    row := db.QueryRow("select id, name, age from user where id=?", id)

    var user User
    err := row.Scan(&amp;user.Id, &amp;user.Name, &amp;user.Age)

    if err == sql.ErrNoRows {
      log.Printf("not found data of the id:%d",id)
    }

    if err != nil {
      panic(err)
    }


    fmt.Printf("user: %#v\n", user)
}


// 多行查询, 查询不到任何记录也不会报错。
func Query(db *sql.DB) {
    id := 0
    rows, err := db.Query("select id, name, age from user where id&gt;?", id)
    if err != nil {
      panic(err)
    }
    if err == sql.ErrNoRows {
      log.Printf("not found data of id:%d\n", id)
      return
    }
    defer rows.Close()

    for rows.Next() {
      var user User
      err := rows.Scan(&amp;user.Id, &amp;user.Name, &amp;user.Age)
      if err != nil {
            panic(err)
      }
      fmt.Printf("user: %#v\n", user)
    }

}

func main() {
    dns := "root:123456@tcp(172.16.65.200:3306)/golang"
    db, err := sql.Open("mysql", dns)
    if err != nil {
      panic(err)
    }

    err = db.Ping()
    if err != nil {
      panic(err)
    }

    fmt.Printf("connect to db success\n")

    //QueryRow(db)

    Query(db)
}</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
</div>
</div>
<p>&nbsp;</p>
<p><strong>事务支持</strong><em id="__mceDel">&nbsp;</em></p>
<p>事务(transaction)</p>
<ul>
<li>transaction, err := Db.Begin() 开启事务</li>
<li>transaction.Exec() 执行事务</li>
<li>transaction.Commit() 提交事务</li>
<li>transaction.Rollback() 回滚事务</li>
</ul>
<p>A. 事务的应用场景<br>  1. 同时更新多个表<br>  2. 同时更新多行数据<br>B. 事务的ACID<br>  1. 原子性<br>  2. 一致性<br>  3. 隔离性<br>  4. 持久性</p>
<p>&nbsp;</p>
<p>需要注意的点:<br>1. 执行失败要回滚<br>2. 提交失败要回滚</p>
<div class="cnblogs_code">
<p>package main</p>
<p>import (<br>    _ "github.com/go-sql-driver/mysql"<br>    "database/sql"<br>    "fmt"<br>)</p>
<p><br>func Transaction(db *sql.DB) {</p>
<p>    // 开启事务<br>    tx, err := db.Begin()</p>
<p>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    result, err := tx.Exec("insert into user(name, age)values(?,?)", "Jack", 98)<br>    if err != nil {<br>      // 失败回滚<br>      tx.Rollback()<br>      panic(err)<br>    }<br>    <br>    fmt.Println("result", result)</p>
<p>    exec, err := tx.Exec("update user set name=?, age=? where id=?", "Jack", 98, 1)<br>    if err != nil {<br>      // 失败回滚<br>      tx.Rollback()<br>      panic(err)<br>    }<br>    fmt.Println("exec", exec)</p>
<p>    // 提交事务<br>    err = tx.Commit()<br>    <br>    if err != nil {<br>      // 失败回滚<br>      tx.Rollback()<br>      panic(err)<br>    }<br>}</p>
<p>func main() {</p>
<p>    dns := "root:123456@tcp(172.16.65.200:3306)/golang"<br>    db, err := sql.Open("mysql", dns)<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    err = db.Ping()<br>    if err != nil {<br>      panic(err)<br>    }</p>
<p>    Transaction(db)<br>}</p>
<br>
<div id="cnblogs_code_open_2d67ac15-6ad2-4481-8320-c1b45e421f5c" class="cnblogs_code_hide">
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
<pre>package main

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


func Transaction(db *sql.DB) {

    // 开启事务
    tx, err := db.Begin()

    if err != nil {
      panic(err)
    }

    result, err := tx.Exec("insert into user(name, age)values(?,?)", "Jack", 98)
    if err != nil {
      // 失败回滚
      tx.Rollback()
      panic(err)
    }
   
    fmt.Println("result", result)

    exec, err := tx.Exec("update user set name=?, age=? where id=?", "Jack", 98, 1)
    if err != nil {
      // 失败回滚
      tx.Rollback()
      panic(err)
    }
    fmt.Println("exec", exec)

    // 提交事务
    err = tx.Commit()
   
    if err != nil {
      // 失败回滚
      tx.Rollback()
      panic(err)
    }
}

func main() {

    dns := "root:123456@tcp(172.16.65.200:3306)/golang"
    db, err := sql.Open("mysql", dns)
    if err != nil {
      panic(err)
    }

    err = db.Ping()
    if err != nil {
      panic(err)
    }

    Transaction(db)
}</pre>
<div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><img src="https://common.cnblogs.com/images/copycode.gif"></span></div>
</div>
</div>
<p>&nbsp;</p>
<h3>Mysql日期时间类型报错</h3>
<pre>sql: Scan error on column index 1: unsupported Scan, storing driver.Value type []uint8 into type *time.Time</pre>
<p>原因是在调用sql.Open()时没有将parseTime设置为True。加入parseTime即可修复问题:</p>
<div class="cnblogs_code">
<pre>db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname?parseTime=true")</pre>
</div><br><br>
来源:https://www.cnblogs.com/show58/p/12373837.html
頁: [1]
查看完整版本: Go Mysql驱动