golang数据库编程
example:
package main
import (
"context"
"database/sql"
"fmt"
"log"
_ "github.com/denisenkom/go-mssqldb"
)
var db *sql.DB
const (
server = "xxx.database.windows.net"
port = 1234
user = "xxx"
password = "xxxxxx"
database = "go-db"
)
func main() {
connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;", server, user, password, port, database)
db, err := sql.Open("sqlserver", connStr)
if err != nil {
log.Fatalln(err.Error())
}
ctx := context.Background()
err = db.PingContext(ctx)
if err != nil {
log.Fatalln(err.Error())
}
fmt.Println("Connected")
}
准备连接到数据库
-
要想连接到
SQL数据库,首先需要加载目标数据库驱动,驱动里面包含着与该数据库交互的逻辑 -
sql.Open()- 数据库驱动的名称
- 数据源名称
- 得到一个指向
sql.DB这个struct的指针
-
sql.DB是用来操作数据库的,它代表了0个或者多个底层连接的池,这些连接由sql包来维护,sql包会自动的创建和释放这些连接- 它对于多个
goroutine并发的使用是安全的
- 它对于多个
NOTE
Open()函数并不会连接数据库,甚至不会验证其参数。它只是把后续连接到数据库所必需的structs给设置好了- 而真正的连接是在被需要的时候才进行懒设置的
sql.DB不需要进行关闭(当然你想关闭也是可以的)- 它就是用来处理数据库的,而不是实际的连接
- 这个抽象包含了数据库连接的池,而且会对此进行维护
- 在使用
sql.DB的时候,可以定义它的全局变量进行使用,也可以将它传递函数/方法里
驱动的获取
正常的做法是使用sql.Register()函数、数据库驱动的名称和一个实现了driver.Driver接口的struct,来注册数据库的驱动。例如:
sql.Register("sqlserver", &dir{})
-
Sql Server的驱动,是在这个包被引入的时候进行了自我注册 -
当
go-mssqldb包被引入到时候,它的init函数将会运行并进行自我注册(在galang语言里,每个包的init函数都会在自动的调用) -
在引入
go-mssqldb包的时候,把该包的名设置为下划线_,这是因为不直接使用数据库驱动,只是用database/sql- 这样如果未来升级驱动,也无需改变代码
-
golang语言没有提供官方的数据库驱动,所有的数据库驱动都是第三方驱动,但是它们都遵循sql.driver包里面定义的接口
安装数据库驱动
-
这是安装
Microsoft SQL Server数据库驱动的例子:go get github.com/denisenkom/go-mssqldb
func (*DB) PingContext
- 上述例子中的
db.PingContext()函数是用来验证与数据库的连接是否仍然有效,如有必要则建立一个连接 - 这个函数需要一个
Context(上下文)类型的参数,这种类型可以携带截止时间,取消信号和其它请求范围的值,并且可以横跨API边界和进程 - 上例中,创建
context使用的是context。Background()函数。该函数返回一个非nil的空Context。它不会被取消,它没有值,没有截止时间 - 它通常用在
main函数、初始化或测试中,作为传入请求的顶级Context
查询
-
sql.DB类型上用于查询的方法有:-
Query// example func getMany(id int) (apps []app, err error) { rows, err := db.Query("SELECT Id, Name, [Order] FROM APP WHERE id>@Id", sql,Named("Id", id)) for rows.Next() { a := app{} err = rows.Scan(&a.ID, &a.name, &a.order) if err != nil { log.Fatalln(err.Error()) } apps = append(apps, a) } return }-
返回的类型是:
type Rows struct{} -
Rows的方法:func (rs *Rows) Close() errorfunc (rs *Rows) ColumnTypes() ([]*ColumnType, error)func (rs *Rows) Columns() ([]strubg, error)func (rs *Rows) Err() errorfunc (rs *Rows) Next() boolfunc (rs *Rows) NextResultSet() boolfunc (rs *Rows) Scan(dest...interface{}) error
-
-
QueryRow// example func getOne(id int) (a app, err error){ a = app{} log.Println(db == nil) err = db.QueryRow("SELECT Id, Name, [Order] FROM APP WHERE Id=@Id", sql.Named("Id", id)).Scan(&a.ID, &a.name, &a.order) return } // example for insert func (a *app) Insert() (err error) { statement := `INSERT INTO APP (Name, NickName, Status, Level, [Order], Pinyin) VALUS (@Name, 'Nick', @Status, @Level, @Order, '...'); SELECT isNull(SCOPE_IDENTITY(), -1);` stmt, err := db.Prepare(statement) if err != nil { log.Fatalln(err.Error()) } defer stmt.Close() err = stmt.QueryRow( sql.Named("Name", a.Name) sql.Named("Status", a.status) sql.Named("Level", a.level) sql.Named("Order", a.order)).Scan(&a.ID) if err != nil { log.Fatalln(err.Error()) } return }-
返回类型是:
type Row struct{} -
Row的方法有:func (r *Row) Err() errorfunc (r *Row) Scan(dest...interface{}) error
-
-
QueryContext -
QueryRowContext
-
更新
-
sql.DB类型上用于更新(执行命令)的方法有:-
Exec// example for update func (a *app) Update() (err error) { _, err = db,Exec("UPDATE APP SET Name=@Name, [Order]=@Order WHERE Id=@Id", sql.Named("Name", a.name), sql.Named("Order ", a.Order), sql.Named("Id", a.Id)) if err != nil { log.Fatalln(err.Error()) } return }// example for delete func (a *app) Delete() (err error) { _, err = db.Exec("DELETE FROM APP WHERE Id=@Id", sql.Named("Id", a.Id)) if err != nil { log.Fatalln(err.Error()) } return } -
ExecContext
-
其他
-
Ping -
PingContext -
Prepare -
PrepareContext -
TransactionsBeginBeginTx