注意:DB并非指的一个connectionmysql
咱们以mysql为例,使用github.com/go-sql-driver/mysql,首先咱们须要导入咱们须要的包git
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 handlegithub
db, err := sql.Open("mysql", "user:password@tcp(ip:port)/database")
写一个完整的:sql
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做为参数传递给方法app
Exec()方法通常用于增删改操做,这里以增长为例:tcp
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()google
var name string err = db.QueryRow("select name from user where id = ?", 222).Scan(&name)
没有结果的时候会返回errurl
咱们用一个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(columns[i], ": ", value) } fmt.Println("-----------------------------------") } if err = rows.Err(); err != nil { panic(err.Error()) // proper error handling instead of panic in your app } }
使用db.Begin()来开启一个事务, 经过Commit()和Rollback()方法来关闭。
tx := db.Begin() tx.Rollback() tx.Commit()
Exec, Query, QueryRow and Prepare 方法已经所有能够在tx上面使用。使用方法和在*sql.DB是同样的,事务必须以Commit()或者Rollback()结束
在database/sql中有一个很基本的链接池,你并无多大的控制权,仅仅能够设置SetMaxIdleConns和SetMaxOpenConns,也就是最大空闲链接和最大链接数。
db.SetMaxIdleConns(n) db.SetMaxOpenConns(n)