基本概念
- Open() – creates a DB
- Close() - closes the DB
- Query() - 查詢
- QueryRow() -查詢行
- Exec() -執行操作,update,insert,delete
- Row - A row is not a hash map, but an abstraction of a cursor
- Next()
- Scan()
注意:DB並不是指的一個connection
連接到數據庫
我們以mysql為例,使用github.com/go-sql-driver/mysql,首先我們需要導入我們需要的包
import ( "database/sql" _ "github.com/go-sql-driver/mysql" )
注意我們導入github.com/go-sql-driver/mysql 前面用了一個"",操作其實是引入該包,而不直接使用包里面的函數,而是調用了該包里面的init函數,import的時候其實是執行了該包里面的init函數,初始化了里面的變量,_操作只是說該包引入了,我只初始化里面的 init函數和一些變量,但是往往這些init函數里面是注冊自己包里面的引擎,讓外部可以方便的使用,就很多實現database/sql的包,在 init函數里面都是調用了sql.Register(name string, driver driver.Driver)注冊自己,然后外部就可以使用了。
我們用Open()函數來打開一個database handle
db, err := sql.Open("mysql", "user:password@tcp(ip:port)/database")
寫一個完整的:
import ( "database/sql" _ "github.com/go-sql-driver/mysql" "log" ) func main() { db, err := sql.Open("mysql", "user:password@tcp(ip:port)/database") if err != nil { log.Println(err) } //在這里進行一些數據庫操作 defer db.Close() }
我們在執行Open函數的時候,並不會去獲得數據庫連接有效性,當執行數據庫操作的時候才會去連接,當我們需要在Open之后就知道連接的有效性的時候,可以通過Ping()來進行
err = db.Ping() if err != nil { log.Println(err) }
我們通常習慣使用Close來關閉數據庫連接,但是sql.DB是被設計成長期有效的類型,我們不應該頻繁的Open和Close,相反,我們應該建立一個sql.DB,在程序需要進行數據庫操作的時候一直使用它,不要在一個方法里面進行Open和Close,應該把sql.DB作為參數傳遞給方法
進行數據庫操作
增刪改操作
Exec()方法一般用於增刪改操作,這里以增加為例:
stmt, err := db.Prepare("insert into user(name,age)values(?,?)") if err != nil { log.Println(err) } rs, err := stmt.Exec("go-test", 12) if err != nil { log.Println(err) } //我們可以獲得插入的id id, err := rs.LastInsertId() //可以獲得影響行數 affect, err := rs.RowsAffected()
查詢操作
一般的查詢
var name string var age int rows, err := db.Query("select name,age from user where id = ? ", 1) if err != nil { fmt.Println(err) } defer rows.Close() for rows.Next() { err := rows.Scan(&name, &age) if err != nil { fmt.Println(err) } } err = rows.Err() if err != nil { fmt.Println(err) } fmt.Println("name:", url, "age:", description)
我們應該養成關閉rows的習慣,在任何時候,都不要忘記rows.Close().哪怕這個rows在確實循環完之后,已經自動關閉掉了,我們定義rows.Close()也是對我們沒有壞處的,因為我們無法保證,rows是否會正常的循環完。
查詢單條記錄,
我們使用db.QueryRow()
var name string err = db.QueryRow("select name from user where id = ?", 222).Scan(&name)
沒有結果的時候會返回err
處理空值
我們用一個name字段為空的記錄來舉例
var name NullString err := db.QueryRow("SELECT name FROM names WHERE id = ?", id).Scan(&name) ... if name.Valid { // use name.String } else { // value is NULL }
在這種情況下我們通常使用NullString,但是有時候我們並不關心值是不是Null,我們只需要吧他當一個空字符串來對待就行。這時候我們可以使用[]byte(null byte[]可以轉化為空string) 或者 sql.RawBytes,
var col1, col2 []byte for rows.Next() { // Scan the value to []byte err = rows.Scan(&col1, &col2) if err != nil { panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic } // Use the string value fmt.Println(string(col1), string(col2)) }
使用*sql.RawBytes
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" ) func main() { // Open database connection db, err := sql.Open("mysql", "user:password@/dbname") if err != nil { panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic } defer db.Close() // Execute the query rows, err := db.Query("SELECT * FROM table") if err != nil { panic(err.Error()) // proper error handling instead of panic in your app } // Get column names columns, err := rows.Columns() if err != nil { panic(err.Error()) // proper error handling instead of panic in your app } // Make a slice for the values values := make([]sql.RawBytes, len(columns)) // rows.Scan wants '[]interface{}' as an argument, so we must copy the // references into such a slice // See http://code.google.com/p/go-wiki/wiki/InterfaceSlice for details scanArgs := make([]interface{}, len(values)) for i := range values { scanArgs[i] = &values[i] } // Fetch rows for rows.Next() { // get RawBytes from data err = rows.Scan(scanArgs...) if err != nil { panic(err.Error()) // proper error handling instead of panic in your app } // Now do something with the data. // Here we just print each column as a string. var value string for i, col := range values { // Here we can check if the value is nil (NULL value) if col == nil { value = "NULL" } else { value = string(col) } fmt.Println