• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            Fork me on GitHub
            隨筆 - 215  文章 - 13  trackbacks - 0
            <2017年4月>
            2627282930311
            2345678
            9101112131415
            16171819202122
            23242526272829
            30123456


            專注即時通訊及網游服務端編程
            ------------------------------------
            Openresty 官方模塊
            Openresty 標準模塊(Opm)
            Openresty 三方模塊
            ------------------------------------
            本博收藏大部分文章為轉載,并在文章開頭給出了原文出處,如有再轉,敬請保留相關信息,這是大家對原創(chuàng)作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            相冊

            Awesome

            Blog

            Book

            GitHub

            Link

            搜索

            •  

            積分與排名

            • 積分 - 216749
            • 排名 - 118

            最新評論

            閱讀排行榜

            http://www.cnblogs.com/tsiangleo/p/4483657.html

            1.下載并導入數(shù)據庫驅動包

            官方不提供實現(xiàn),先下載第三方的實現(xiàn),點擊這里查看各種各樣的實現(xiàn)版本。
            這里選擇了Go-MySQL-Driver這個實現(xiàn)。地址是:https://github.com/go-sql-driver/mysql/

            然后按照里面的說明下載驅動包:

            $ go get github.com/go-sql-driver/mysql

            最后導入包即可:

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

            2.連接至數(shù)據庫

            db, err := sql.Open("mysql", "root:root@/uestcbook")

            3.執(zhí)行查詢

            (1)Exec 

            result, err := db.Exec(
                "INSERT INTO users (name, age) VALUES (?, ?)",
                "gopher",
                27,
            )

             

            (2)Query 

            復制代碼
            rows, err := db.Query("SELECT name FROM users WHERE age = ?", age)
            if err != nil {
                log.Fatal(err)
            }
            for rows.Next() {
                var name string
                if err := rows.Scan(&name); err != nil {
                    log.Fatal(err)
                }
                fmt.Printf("%s is %d\n", name, age)
            }
            if err := rows.Err(); err != nil {
                log.Fatal(err)
            }
            復制代碼

             

            (3)QueryRow

            var age int64
            row := db.QueryRow("SELECT age FROM users WHERE name = ?", name)
            err := row.Scan(&age)

             

             

            (4)Prepared statements 

            復制代碼
            age := 27
            stmt, err := db.Prepare("SELECT name FROM users WHERE age = ?")
            if err != nil {
                log.Fatal(err)
            }
            rows, err := stmt.Query(age)
            // process rows
            復制代碼

             

             

            4. 事務

            tx, err := db.Begin()
            if err != nil {
                log.Fatal(err)
            }

             

             

            5. 各種方式效率分析

            問題:db.exec和statement.exec和tx.exec的區(qū)別?

            實例如下:

            復制代碼
            package main
            
            import (
                "strconv"
                "database/sql"
                _ "github.com/go-sql-driver/mysql"
                "fmt"
                "time"
                "log"
            )
            
            var db = &sql.DB{}
            
            func init(){
                db,_ = sql.Open("mysql", "root:root@/book")
            } 
            
            func main() {
                insert()
                query()
                update()
                query()
                delete()
            }
            
            func update(){
                //方式1 update
                start := time.Now()
                for i := 1001;i<=1100;i++{
                    db.Exec("UPdate user set age=? where uid=? ",i,i)
                }
                end := time.Now()
                fmt.Println("方式1 update total time:",end.Sub(start).Seconds())
                
                //方式2 update
                start = time.Now()
                for i := 1101;i<=1200;i++{
                    stm,_ := db.Prepare("UPdate user set age=? where uid=? ")
                    stm.Exec(i,i)
                    stm.Close()
                }
                end = time.Now()
                fmt.Println("方式2 update total time:",end.Sub(start).Seconds())
                
                //方式3 update
                start = time.Now()
                stm,_ := db.Prepare("UPdate user set age=? where uid=?")
                for i := 1201;i<=1300;i++{
                    stm.Exec(i,i)
                }
                stm.Close()
                end = time.Now()
                fmt.Println("方式3 update total time:",end.Sub(start).Seconds())
                
                //方式4 update
                start = time.Now()
                tx,_ := db.Begin()
                for i := 1301;i<=1400;i++{
                    tx.Exec("UPdate user set age=? where uid=?",i,i)
                }
                tx.Commit()
                
                end = time.Now()
                fmt.Println("方式4 update total time:",end.Sub(start).Seconds())
                
                //方式5 update
                start = time.Now()
                for i := 1401;i<=1500;i++{
                    tx,_ := db.Begin()
                    tx.Exec("UPdate user set age=? where uid=?",i,i)
                    tx.Commit()
                }
                end = time.Now()
                fmt.Println("方式5 update total time:",end.Sub(start).Seconds())
                
            }
            
            func delete(){
                //方式1 delete
                start := time.Now()
                for i := 1001;i<=1100;i++{
                    db.Exec("DELETE FROM USER WHERE uid=?",i)
                }
                end := time.Now()
                fmt.Println("方式1 delete total time:",end.Sub(start).Seconds())
                
                //方式2 delete
                start = time.Now()
                for i := 1101;i<=1200;i++{
                    stm,_ := db.Prepare("DELETE FROM USER WHERE uid=?")
                    stm.Exec(i)
                    stm.Close()
                }
                end = time.Now()
                fmt.Println("方式2 delete total time:",end.Sub(start).Seconds())
                
                //方式3 delete
                start = time.Now()
                stm,_ := db.Prepare("DELETE FROM USER WHERE uid=?")
                for i := 1201;i<=1300;i++{
                    stm.Exec(i)
                }
                stm.Close()
                end = time.Now()
                fmt.Println("方式3 delete total time:",end.Sub(start).Seconds())
                
                //方式4 delete
                start = time.Now()
                tx,_ := db.Begin()
                for i := 1301;i<=1400;i++{
                    tx.Exec("DELETE FROM USER WHERE uid=?",i)
                }
                tx.Commit()
                
                end = time.Now()
                fmt.Println("方式4 delete total time:",end.Sub(start).Seconds())
                
                //方式5 delete
                start = time.Now()
                for i := 1401;i<=1500;i++{
                    tx,_ := db.Begin()
                    tx.Exec("DELETE FROM USER WHERE uid=?",i)
                    tx.Commit()
                }
                end = time.Now()
                fmt.Println("方式5 delete total time:",end.Sub(start).Seconds())
                
            }
            
            func query(){
                
                //方式1 query
                start := time.Now()
                rows,_ := db.Query("SELECT uid,username FROM USER")
                defer rows.Close()
                for rows.Next(){
                     var name string
                     var id int
                    if err := rows.Scan(&id,&name); err != nil {
                        log.Fatal(err)
                    }
                    //fmt.Printf("name:%s ,id:is %d\n", name, id)
                }
                end := time.Now()
                fmt.Println("方式1 query total time:",end.Sub(start).Seconds())
                
                //方式2 query
                start = time.Now()
                stm,_ := db.Prepare("SELECT uid,username FROM USER")
                defer stm.Close()
                rows,_ = stm.Query()
                defer rows.Close()
                for rows.Next(){
                     var name string
                     var id int
                    if err := rows.Scan(&id,&name); err != nil {
                        log.Fatal(err)
                    }
                   // fmt.Printf("name:%s ,id:is %d\n", name, id)
                }
                end = time.Now()
                fmt.Println("方式2 query total time:",end.Sub(start).Seconds())
                
                
                //方式3 query
                start = time.Now()
                tx,_ := db.Begin()
                defer tx.Commit()
                rows,_ = tx.Query("SELECT uid,username FROM USER")
                defer rows.Close()
                for rows.Next(){
                     var name string
                     var id int
                    if err := rows.Scan(&id,&name); err != nil {
                        log.Fatal(err)
                    }
                    //fmt.Printf("name:%s ,id:is %d\n", name, id)
                }
                end = time.Now()
                fmt.Println("方式3 query total time:",end.Sub(start).Seconds())
            }
            
            func insert() {
                
                //方式1 insert
                //strconv,int轉string:strconv.Itoa(i)
                start := time.Now()
                for i := 1001;i<=1100;i++{
                    //每次循環(huán)內部都會去連接池獲取一個新的連接,效率低下
                    db.Exec("INSERT INTO user(uid,username,age) values(?,?,?)",i,"user"+strconv.Itoa(i),i-1000)
                }
                end := time.Now()
                fmt.Println("方式1 insert total time:",end.Sub(start).Seconds())
                
                //方式2 insert
                start = time.Now()
                for i := 1101;i<=1200;i++{
                    //Prepare函數(shù)每次循環(huán)內部都會去連接池獲取一個新的連接,效率低下
                    stm,_ := db.Prepare("INSERT INTO user(uid,username,age) values(?,?,?)")
                    stm.Exec(i,"user"+strconv.Itoa(i),i-1000)
                    stm.Close()
                }
                end = time.Now()
                fmt.Println("方式2 insert total time:",end.Sub(start).Seconds())
                
                //方式3 insert
                start = time.Now()
                stm,_ := db.Prepare("INSERT INTO user(uid,username,age) values(?,?,?)")
                for i := 1201;i<=1300;i++{
                    //Exec內部并沒有去獲取連接,為什么效率還是低呢?
                    stm.Exec(i,"user"+strconv.Itoa(i),i-1000)
                }
                stm.Close()
                end = time.Now()
                fmt.Println("方式3 insert total time:",end.Sub(start).Seconds())
                
                //方式4 insert
                start = time.Now()
                //Begin函數(shù)內部會去獲取連接
                tx,_ := db.Begin()
                for i := 1301;i<=1400;i++{
                    //每次循環(huán)用的都是tx內部的連接,沒有新建連接,效率高
                    tx.Exec("INSERT INTO user(uid,username,age) values(?,?,?)",i,"user"+strconv.Itoa(i),i-1000)
                }
                //最后釋放tx內部的連接
                tx.Commit()
                
                end = time.Now()
                fmt.Println("方式4 insert total time:",end.Sub(start).Seconds())
                
                //方式5 insert
                start = time.Now()
                for i := 1401;i<=1500;i++{
                    //Begin函數(shù)每次循環(huán)內部都會去連接池獲取一個新的連接,效率低下
                    tx,_ := db.Begin()
                    tx.Exec("INSERT INTO user(uid,username,age) values(?,?,?)",i,"user"+strconv.Itoa(i),i-1000)
                    //Commit執(zhí)行后連接也釋放了
                    tx.Commit()
                }
                end = time.Now()
                fmt.Println("方式5 insert total time:",end.Sub(start).Seconds())
            }
            復制代碼

            程序輸出結果:

            方式1 insert total time: 3.7952171
            方式2 insert total time: 4.3162468
            方式3 insert total time: 4.3392482
            方式4 insert total time: 0.3970227
            方式5 insert total time: 7.3894226
            方式1 query total time: 0.0070004
            方式2 query total time: 0.0100006
            方式3 query total time: 0.0100006
            方式1 update total time: 7.3394198
            方式2 update total time: 7.8464488
            方式3 update total time: 6.0053435
            方式4 update total time: 0.6630379000000001
            方式5 update total time: 4.5402597
            方式1 query total time: 0.0070004
            方式2 query total time: 0.0060004
            方式3 query total time: 0.008000400000000001
            方式1 delete total time: 3.8652211000000003
            方式2 delete total time: 3.8582207
            方式3 delete total time: 3.6972114
            方式4 delete total time: 0.43202470000000004
            方式5 delete total time: 3.7972172

             

            6. 深入內部分析原因分析

            (1)sql.Open("mysql", "username:pwd@/databasename")

            功能:返回一個DB對象,DB對象對于多個goroutines并發(fā)使用是安全的,DB對象內部封裝了連接池。

            實現(xiàn):open函數(shù)并沒有創(chuàng)建連接,它只是驗證參數(shù)是否合法。然后開啟一個單獨goroutines去監(jiān)聽是否需要建立新的連接,當有請求建立新連接時就創(chuàng)建新連接。

            注意:open函數(shù)應該被調用一次,通常是沒必要close的。

             

            (2)DB.Exec()

            功能:執(zhí)行不返回行(row)的查詢,比如INSERT,UPDATE,DELETE

            實現(xiàn):DB交給內部的exec方法負責查詢。exec會首先調用DB內部的conn方法從連接池里面獲得一個連接。然后檢查內部的driver.Conn實現(xiàn)了Execer接口沒有,如果實現(xiàn)了該接口,會調用Execer接口的Exec方法執(zhí)行查詢;否則調用Conn接口的Prepare方法負責查詢。

             

            (3)DB.Query()

            功能:用于檢索(retrieval),比如SELECT

            實現(xiàn):DB交給內部的query方法負責查詢。query首先調用DB內部的conn方法從連接池里面獲得一個連接,然后調用內部的queryConn方法負責查詢。

             

            (4)DB.QueryRow()

            功能:用于返回單行的查詢

            實現(xiàn):轉交給DB.Query()查詢

             

            (5)db.Prepare()

            功能:返回一個Stmt。Stmt對象可以執(zhí)行Exec,Query,QueryRow等操作。

            實現(xiàn):DB交給內部的prepare方法負責查詢。prepare首先調用DB內部的conn方法從連接池里面獲得一個連接,然后調用driverConn的prepareLocked方法負責查詢。

            Stmt相關方法:

            st.Exec()

            st.Query()

            st.QueryRow()

            st.Close()

             

            (6)db.Begin()

            功能:開啟事務,返回Tx對象。調用該方法后,這個TX就和指定的連接綁定在一起了。一旦事務提交或者回滾,該事務綁定的連接就還給DB的連接池。

            實現(xiàn):DB交給內部的begin方法負責處理。begin首先調用DB內部的conn方法從連接池里面獲得一個連接,然后調用Conn接口的Begin方法獲得一個TX。

            TX相關方法:

            //內部執(zhí)行流程和上面那些差不多,只是沒有先去獲取連接的一步,因為這些操作是和TX關聯(lián)的,Tx建立的時候就和一個連接綁定了,所以這些操作內部共用一個TX內部的連接。

            tx.Exec() 

            tx.Query()

            tx.QueryRow()

            tx.Prepare()

            tx.Commit()

            tx.Rollback()

            tx.Stmt()//用于將一個已存在的statement和tx綁定在一起。一個statement可以不和tx關聯(lián),比如db.Prepare()返回的statement就沒有和TX關聯(lián)。

            例子:

            復制代碼
              updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
            
              ...
            
              tx, err := db.Begin()
            
              ...
            
              res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
            復制代碼

             

             (7)源碼中Stmt的定義

            復制代碼
            // Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
            
            type Stmt struct {
            
                     // Immutable:
            
                     db        *DB    // where we came from
            
                     query     string // that created the Stmt
            
                     stickyErr error  // if non-nil, this error is returned for all operations
            
             
            
                     closemu sync.RWMutex // held exclusively during close, for read otherwise.
            
             
            
                     // If in a transaction, else both nil:
            
                     tx   *Tx
            
                     txsi *driverStmt
            
             
            
                     mu     sync.Mutex // protects the rest of the fields
            
                     closed bool
            
             
            
                     // css is a list of underlying driver statement interfaces
            
                     // that are valid on particular connections.  This is only
            
                     // used if tx == nil and one is found that has idle
            
                     // connections.  If tx != nil, txsi is always used.
            
                     css []connStmt
            
            }
            復制代碼

             

            (7)幾個主要struct的內部主要的數(shù)據結構

             

            參考資料

            https://github.com/golang/go/wiki/SQLInterface

            https://github.com/go-sql-driver/mysql/

            http://golang.org/pkg/database/sql/

            posted on 2017-04-18 14:11 思月行云 閱讀(927) 評論(1)  編輯 收藏 引用 所屬分類: Golang

            FeedBack:
            # re: Golang操作MySql數(shù)據庫 2017-04-18 16:29 思月行云
            select多個字段時的寫法:

            //查詢數(shù)據
            rows, err := db.Query("SELECT * FROM userinfo")
            checkErr(err)

            for rows.Next() {
            var uid int
            var username string
            var department string
            var created string
            err = rows.Scan(&uid, &username, &department, &created)
            checkErr(err)
            fmt.Println(uid)
            fmt.Println(username)
            fmt.Println(department)
            fmt.Println(created)
            }   回復  更多評論
              
            国产精品久久久久AV福利动漫| 亚洲伊人久久精品影院| 欧美精品福利视频一区二区三区久久久精品| 久久精品这里只有精99品| 日产精品99久久久久久| 久久99毛片免费观看不卡 | 成人亚洲欧美久久久久| 久久美女网站免费| 狠狠色丁香久久婷婷综合图片| 精品久久8x国产免费观看| 国产A三级久久精品| 99久久人妻无码精品系列| 久久久久无码中| 久久无码人妻一区二区三区| 国产日韩久久久精品影院首页| 国内精品伊人久久久影院| 亚洲AV无码一区东京热久久| 无码乱码观看精品久久| 精品久久久久久中文字幕| 久久精品亚洲欧美日韩久久| 午夜精品久久久久久久久| 国产一区二区精品久久岳| 精品乱码久久久久久久| 欧美国产精品久久高清| 国内精品久久国产大陆| 99久久无色码中文字幕人妻| 国产日韩欧美久久| 久久国产精品久久| 久久国产精品成人影院| 久久久精品2019免费观看| 天天综合久久一二三区| 国产午夜精品理论片久久| 国产精品99精品久久免费| 伊人久久久AV老熟妇色| 人人狠狠综合久久亚洲| 国内精品伊人久久久久网站| 99精品久久精品一区二区| 99久久99这里只有免费的精品| 欧美va久久久噜噜噜久久| 中文字幕无码久久精品青草 | 伊人久久大香线蕉AV一区二区|