安裝mysql驅動:
go get -u github.com/go-sql-driver/mysql
初始化模塊
go mod init m
執行
go mod tidy
導入包:
package main import ( "fmt" "database/sql" _ "github.com/go-sql-driver/mysql" )
獲得鏈接:
package main import ( "database/sql" _ "github.com/go-sql-driver/mysql" "time" ) func main() { db, err := sql.Open("mysql", "root:123456@/go_db") if err != nil { panic(err) } print(db) // 最大連接時長 db.SetConnMaxLifetime(time.Minute * 3) // 最大連接數 db.SetMaxOpenConns(10) // 空閑連接數 db.SetMaxIdleConns(10) }
初始化連接
Open函數可能只是驗證其參數格式是否正確,實際上並不創建與數據庫的連接。如果要檢查數據源的名稱是否真實有效,應該調用Ping方法。
返回的DB對象可以安全地被多個goroutine並發使用,並且維護其自己的空閑連接池。因此,Open函數應該僅被調用一次,很少需要關閉這個DB對象。
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" ) // 定義一個全局對象db var db2 *sql.DB // 定義一個初始化數據庫的函數 func initDB() (err error) { dsn := "root:123456@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True" // 不會校驗賬號密碼是否正確 // 注意!!!這里不要使用:=,我們是給全局變量賦值,然后在main函數中使用全局變量db db2, err = sql.Open("mysql", dsn) if err != nil { return err } // 嘗試與數據庫建立連接(校驗dsn是否正確) err = db2.Ping() if err != nil { return err } return nil } func main() { err := initDB() // 調用輸出化數據庫的函數 if err != nil { fmt.Printf("初始化失敗!,err:%v\n", err) return }else{ fmt.Printf("初始化成功") } }
當行查詢:
單行查詢db.QueryRow()
執行一次查詢,並期望返回最多一行結果(即Row)。QueryRow總是返回非nil的值,直到返回值的Scan方法被調用時,才會返回被延遲的錯誤。
定義結構體:
type user struct { id int username string password string }
// 查詢一條用戶數據 func queryRowDemo() { sqlStr := "select id, username, password from user_tbl where id=?" var u user // 確保QueryRow之后調用Scan方法,否則持有的數據庫鏈接不會被釋放 err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.username, &u.password) if err != nil { fmt.Printf("scan failed, err:%v\n", err) return } fmt.Printf("id:%d name:%s age:%s\n", u.id, u.username, u.password) }
func main() { err := initDB() // 調用輸出化數據庫的函數 if err != nil { fmt.Printf("初始化失敗!,err:%v\n", err) return }else{ fmt.Printf("初始化成功") } queryRowDemo() }
查詢多行
多行查詢db.Query()
執行一次查詢,返回多行結果(即Rows),一般用於執行select命令。參數args表示query中的占位參數。
// 查詢多條數據示例 func queryMultiRow() { sqlStr := "select id, username, password from user_tbl where id > ?" rows, err := db.Query(sqlStr, 0) if err != nil { fmt.Printf("query failed, err:%v\n", err) return } // 非常重要:關閉rows釋放持有的數據庫鏈接 defer rows.Close() // 循環讀取結果集中的數據 for rows.Next() { var u user err := rows.Scan(&u.id, &u.username, &u.password) if err != nil { fmt.Printf("scan failed, err:%v\n", err) return } fmt.Printf("id:%d username:%s password:%s\n", u.id, u.username, u.password) } }
插入,更新和刪除操作都使用Exec方法
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
新增: // 插入數據 func insertData() { sqlStr := "insert into user_tbl(username,password) values (?,?)" ret, err := db.Exec(sqlStr, "張三", "zs123") if err != nil { fmt.Printf("insert failed, err:%v\n", err) return } theID, err := ret.LastInsertId() // 新插入數據的id if err != nil { fmt.Printf("get lastinsert ID failed, err:%v\n", err) return } fmt.Printf("insert success, the id is %d.\n", theID) } 刪除: func delData() { sql := "delete from user_tbl where id =?" ret, err := db.Exec(sql, "1") if err != nil { fmt.Printf("刪除失敗, err:%v\n", err) return } rows, err := ret.RowsAffected() if err != nil { fmt.Printf("刪除行失敗, err:%v\n", err) return } fmt.Printf("刪除成功, 刪除的行數:%d.\n", rows) } 更新: func updateData() { sql := "update user_tbl set username=?, password=? where id=?" ret, err := db.Exec(sql, "kite2", "kite123", "2") if err != nil { fmt.Printf("更新失敗, err:%v\n", err) return } rows, err := ret.RowsAffected() if err != nil { fmt.Printf("更新行失敗, err:%v\n", err) return } fmt.Printf("更新成功, 更新的行數:%d.\n", rows) }
注意點:
1.表名不能作為占位符使用
"DELETE FROM `?` WHERE created_date BETWEEN ? AND ?" ret, err := db3.Exec(sql, tableName, startDate, endDate)
2.dsn中用戶名和密碼 如果包含特殊字符:!@#^*等,需要進行urlencode處理
url.QueryEscape