一、driver简介

database/sql 是一个给sql-like数据库使用的官方库,主要实现了

  1. driver (sql-like)数据库的驱动接口
  2. sql相关的方法

在地址 https://github.com/golang/go/wiki/SQLDrivers有具体实现了database/sql的sql-like驱动库列表

在这里用了一个策略模式的编程方式。
在 go源码 src/database/sql/sql.go
有一个注册driver方法:

func Register(name string, driver driver.Driver) {
    driversMu.Lock()
    defer driversMu.Unlock()
    if driver == nil {
        panic("sql: Register driver is nil")
    }
    if _, dup := drivers[name]; dup {
        panic("sql: Register called twice for driver " + name)
    }
    drivers[name] = driver
}

在每一个driver驱动实现,都会调用这个方法。
比如mysql驱动go-sql-driver的实现如下:
在源码 github.com/go-sql-driver/mysql/drver.go

func init() {
    sql.Register("mysql", &MySQLDriver{})
}

就把go-sql-driver驱动实现,注入到了database/sql中了。
然后我们使用的时候,就可以这样用了:

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "testing"
)

func TestOpen(t *testing.T) {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/database?charset=utf8")
    t.Log(db, err)
}

在这里我们引用了 _ "github.com/go-sql-driver/mysql"
但却使用 database/sql 里面的方法,因为go-sql-driver只是一个实现。
因为在go-sql-driver我们注册了 "mysql" 的值,然后就可以在database/sql调用了。

二、open一个新的Connection连接

src/database/sql/driver/driver.go 有一个接口定义:

type Driver interface {
    // Open returns a new connection to the database.
    // The name is a string in a driver-specific format.
    //
    // Open may return a cached connection (one previously
    // closed), but doing so is unnecessary; the sql package
    // maintains a pool of idle connections for efficient re-use.
    //
    // The returned connection is only used by one goroutine at a
    // time.
    Open(name string) (Conn, error)
}

新建一个只能一个协程使用的连接
github.com/go-sql-driver/mysql/drver.go 实现如下:

// Open new Connection.
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
// the DSN string is formatted
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
    cfg, err := ParseDSN(dsn)
    if err != nil {
        return nil, err
    }
    c := &connector{
        cfg: cfg,
    }
    return c.Connect(context.Background())
}

使用如下:

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "testing"
)

func TestOpen(t *testing.T) {
    conn, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/database?charset=utf8")
    t.Log(conn, err)
}

使用sql.Open()方法即可获得一个sql.DB实例。需要注意的是,sql.DB的设计就是用来作为长连接使用的,不应该在项目里频繁的进行Open()与Close(),提倡的做法是声明一个全局的sql.DB实例, 将其复用起来。即只Open()一次,使用直到程序结束任务。
可以看到 Open(name string) (Conn, error)
返回一个 driver.Conn 接口如下:
src/database/sql/driver/driver.go 有一个接口定义:

// Conn is a connection to a database. It is not used concurrently
// by multiple goroutines.
//
// Conn is assumed to be stateful.
type Conn interface {
    // Prepare returns a prepared statement, bound to this connection.
    Prepare(query string) (Stmt, error)

    // Close invalidates and potentially stops any current
    // prepared statements and transactions, marking this
    // connection as no longer in use.
    //
    // Because the sql package maintains a free pool of
    // connections and only calls Close when there's a surplus of
    // idle connections, it shouldn't be necessary for drivers to
    // do their own connection caching.
    Close() error

    // Begin starts and returns a new transaction.
    //
    // Deprecated: Drivers should implement ConnBeginTx instead (or additionally).
    Begin() (Tx, error)
}

在这里。

谢谢您的观看,欢迎关注我的公众号。

image.png


海生
104 声望32 粉丝

与黑夜里,追求那一抹萤火。