database/sql
go-sql-driverdatabase/sql
我们查询MySQL的大体代码demo如下:
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
var DB *sql.DB
var dataBase = "root:[email protected](127.0.0.1:3306)/?loc=Local&parseTime=true"
func main() {
var err error
DB, err = sql.Open("mysql", dataBase)
if err != nil {
log.Fatalln("open db fail:", err)
}
var connection_id int
err := DB.QueryRow("select CONNECTION_ID()").Scan(&connection_id)
if err != nil {
log.Println("query connection id failed:", err)
return
}
log.Println("connection id:", connection_id)
}
go-sql-driver
1.驱动注册
驱动注册代码:
func init() {
sql.Register("mysql", &MySQLDriver{})
}
github.com/go-sql-driver/mysql/driver.go
上面的demo中,却看到这个操作。
那是什么时候做的呢?
答案是import 的时候:
import (
_ "github.com/go-sql-driver/mysql"
)
接着看下Register 函数的实现:
// Register makes a database driver available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
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
}
其中,drivers是一个map,定义为:
var (
drivers = make(map[string]driver.Driver)
)
RegisterMySQLDrivermysql
Registerdriver.Driver
接口定义如下:
// Driver is the interface that must be implemented by a database
// driver.
//
// Database drivers may implement DriverContext for access
// to contexts and to parse the name only once for a pool of connections,
// instead of once per connection.
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)
}
OpenMySQLDriver
go-sql-drivergithub.com/go-sql-driver/mysql/driver.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) {
... ...
// New mysqlConn
mc := &mysqlConn{
maxAllowedPacket: maxPacketSize,
maxWriteSize: maxPacketSize - 1,
closech: make(chan struct{}),
}
... ...
return mc, nil
}
2.打开一个database
DB, err = sql.Open("mysql", dataBase)
第一个参数是driver名称,第二个参数是dsn(DataSourceName),指数据库地址。
driversmysqlDB
DB
type DB struct {
connector driver.Connector
... ...
}
type dsnConnector struct {
dsn string
driver driver.Driver
}
func (t dsnConnector) Connect(_ context.Context) (driver.Conn, error) {
return t.driver.Open(t.dsn)
}
func (t dsnConnector) Driver() driver.Driver {
return t.driver
}
3.查询
var connection_id int
err := DB.QueryRow("select CONNECTION_ID()").Scan(&connection_id)
if err != nil {
log.Println("query connection id failed:", err)
return
}
log.Println("connection id:", connection_id)
底层调用关系是这样的:
func (db *DB) QueryRow()
-->db.QueryRowContext()
-->db.QueryContext()
--> db.conn() --> 最后调用的是MySQLDriver.Open()
--> db.queryDC() --> 最后调用的是mysqlConn.Query()
具体调用关系如下图所示。

其他的查询也是类似的调用过程。
MySQLDriver
4.参考