golang database实验1 | 青训营

59 阅读3分钟

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() error
        • func (rs *Rows) ColumnTypes() ([]*ColumnType, error)
        • func (rs *Rows) Columns() ([]strubg, error)
        • func (rs *Rows) Err() error
        • func (rs *Rows) Next() bool
        • func (rs *Rows) NextResultSet() bool
        • func (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() error
        • func (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

  • Transactions

    • Begin
    • BeginTx