1. 程式人生 > 資料庫 >Golang操作MySql資料庫的完整步驟記錄

Golang操作MySql資料庫的完整步驟記錄

前言

MySQL是業界常用的關係型資料庫,在平時開發中會經常與MySql資料庫打交道,所以在接下來將介紹怎麼使用Go語言操作MySql資料庫。

下載MySql連線驅動

Go語言中的database/sql包提供了保證SQL或類SQL資料庫的泛用介面,並不提供具體的資料庫驅動。使用database/sql包時必須注入(至少)一個數據庫驅動。

我們常用的資料庫基本上都有完整的第三方實現。比如:MySQL驅動

**下載依賴**

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

**使用MySql驅動**

func Open(driverName,dataSourceName string) (*DB,error)

Open開啟一個dirverName指定的資料庫,dataSourceName指定資料來源,一般至少包括資料庫檔名和其它連線必要的資訊。

示例程式碼:

import ( "database/sql"​ _ "github.com/go-sql-driver/mysql")​func main() { // DSN:Data Source Name dsn := "user:password@tcp(127.0.0.1:3306)/dbname" db,err := sql.Open("mysql",dsn) if err != nil { panic(err) } defer db.Close() // 注意這行程式碼要寫在上面err判斷的下面}

初始化連線

Open函式可能只是驗證其引數格式是否正確,實際上並不建立與資料庫的連線。如果要檢查資料來源的名稱是否真實有效,應該呼叫Ping方法。

返回的DB物件可以安全地被多個goroutine併發使用,並且維護其自己的空閒連線池。因此,Open函式應該僅被呼叫一次,很少需要關閉這個DB物件。

示例程式碼如下:

// 定義一個全域性物件dbvar db *sql.DB​// 定義一個初始化資料庫的函式func initDB() (err error) { // DSN:Data Source Name dsn := "user:password@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True" // 不會校驗賬號密碼是否正確 // 注意!!!這裡不要使用:=,我們是給全域性變數賦值,然後在main函式中使用全域性變數db db,err = sql.Open("mysql",dsn) if err != nil { return err } // 嘗試與資料庫建立連線(校驗dsn是否正確) err = db.Ping() if err != nil { return err } return nil}​func main() { err := initDB() // 呼叫輸出化資料庫的函式 if err != nil { fmt.Printf("init db failed,err:%v\n",err) return }}

其中sql.DB是表示連線的資料庫物件(結構體例項),它儲存了連線資料庫相關的所有資訊。它內部維護著一個具有零到多個底層連線的連線池,它可以安全地被多個goroutine同時使用。

**設定最大連線數**

func (db *DB) SetMaxOpenConns(n int)

SetMaxOpenConns設定與資料庫建立連線的最大數目。如果n大於0且小於最大閒置連線數,會將最大閒置連線數減小到匹配最大開啟連線數的限制。如果n<=0,不會限制最大開啟連線數,預設為0(無限制)。

**設定最大閒置連線數**

func (db *DB) SetMaxIdleConns(n int)

SetMaxIdleConns設定連線池中的最大閒置連線數。如果n大於最大開啟連線數,則新的最大閒置連線數會減小到匹配最大開啟連線數的限制。如果n<=0,不會保留閒置連線。

MySql建庫建表

我們先在MySQL中建立一個名為`sql_test`的資料庫:

CREATE DATABASE sql_test;

進入該資料庫:

use sql_test;

執行以下命令建立一張用於測試的資料表:

CREATE TABLE `user` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT,`name` VARCHAR(20) DEFAULT '',`age` INT(11) DEFAULT '0',PRIMARY KEY(`id`))ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

操作MySql查詢

為了方便查詢,我們事先定義好一個結構體來儲存user表的資料。

type user struct { id int age int name string}

**單行查詢**

單行查詢`db.QueryRow()`執行一次查詢,並期望返回最多一行結果(即Row)。QueryRow總是返回非nil的值,直到返回值的Scan方法被呼叫時,才會返回被延遲的錯誤。(如:未找到結果)

func (db *DB) QueryRow(query string,args ...interface{}) *Row

示例程式碼:

// 查詢單條資料示例func queryRowDemo() { sqlStr := "select id,name,age from user where id=?" var u user // 非常重要:確保QueryRow之後呼叫Scan方法,否則持有的資料庫連結不會被釋放 err := db.QueryRow(sqlStr,1).Scan(&u.id,&u.name,&u.age) if err != nil { fmt.Printf("scan failed,err) return } fmt.Printf("id:%d name:%s age:%d\n",u.id,u.name,u.age)}

**多行查詢**

多行查詢db.Query()執行一次查詢,返回多行結果(即Rows),一般用於執行select命令。引數args表示query中的佔位引數。

func (db *DB) Query(query string,args ...interface{}) (*Rows,error)

示例程式碼:

// 查詢多條資料示例func queryMultiRowDemo() { sqlStr := "select id,age from user where id > ?" rows,err := db.Query(sqlStr,0) if err != nil { fmt.Printf("query failed,err) return } // 非常重要:關閉rows釋放持有的資料庫連結 defer rows.Close()​ // 迴圈讀取結果集中的資料 for rows.Next() { var u user err := rows.Scan(&u.id,&u.age) if err != nil {  fmt.Printf("scan failed,err)  return } fmt.Printf("id:%d name:%s age:%d\n",u.age) }}

操作MySql插入資料

插入、更新和刪除操作都使用Exec方法。

func (db *DB) Exec(query string,args ...interface{}) (Result,error)

Exec執行一次命令(包括查詢、刪除、更新、插入等),返回的Result是對已執行的SQL命令的總結。引數args表示query中的佔位引數。

具體插入資料示例程式碼如下:

// 插入資料func insertRowDemo() { sqlStr := "insert into user(name,age) values (?,?)" ret,err := db.Exec(sqlStr,"王五",38) if err != nil { fmt.Printf("insert failed,err) return } theID,err := ret.LastInsertId() // 新插入資料的id if err != nil { fmt.Printf("get lastinsert ID failed,err) return } fmt.Printf("insert success,the id is %d.\n",theID)}

操作MySql更新資料

具體更新資料示例程式碼如下:

// 更新資料func updateRowDemo() { sqlStr := "update user set age=? where id = ?" ret,39,3) if err != nil { fmt.Printf("update failed,err) return } n,err := ret.RowsAffected() // 操作影響的行數 if err != nil { fmt.Printf("get RowsAffected failed,err) return } fmt.Printf("update success,affected rows:%d\n",n)}

操作MySql刪除資料

具體刪除資料的示例程式碼如下:

// 刪除資料func deleteRowDemo() { sqlStr := "delete from user where id = ?" ret,3) if err != nil { fmt.Printf("delete failed,err) return } fmt.Printf("delete success,n)}

SQL注入安全問題

我們任何時候都不應該自己拼接SQL語句!

這裡我們演示一個自行拼接SQL語句的示例,編寫一個根據name欄位查詢user表的函式如下:

// sql注入示例func sqlInjectDemo(name string) { sqlStr := fmt.Sprintf("select id,age from user where name='%s'",name) fmt.Printf("SQL:%s\n",sqlStr) var u user err := db.QueryRow(sqlStr).Scan(&u.id,&u.age) if err != nil { fmt.Printf("exec failed,err) return } fmt.Printf("user:%#v\n",u)}

此時以下輸入字串都可以引發SQL注入問題:

sqlInjectDemo("xxx' or 1=1#")sqlInjectDemo("xxx' union select * from user #")sqlInjectDemo("xxx' and (select count(*) from user) <10 #")

完整示例程式碼歸檔GitHub

Golang操作MySql資料庫示例程式碼

到此這篇關於Golang操作MySql資料庫的完整步驟記錄的文章就介紹到這了,更多相關Golang操作MySql資料庫內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!