Go语言 sql
Golang操作数据库 - 纵酒挥刀斩人头 - 博客园
基本概念
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
user@unix(/path/to/socket)/dbname?charset=utf8
user:password@tcp(localhost:5555)/dbname?charset=utf8
user:password@/dbname
user:password@tcp([de:ad:be:ef::ca:fe]:80)/dbname
我们在执行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
```go
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// 1. 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()
// 2. 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
}
defer rows.Close()
// 3. 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()结束
The Connection Pool
在database/sql中有一个很基本的连接池,你并没有多大的控制权,仅仅可以设置SetMaxIdleConns和SetMaxOpenConns,也就是最大空闲连接和最大连接数。
db.SetMaxIdleConns(n)
db.SetMaxOpenConns(n)