database.sql 库-策略模式
策略模式简介
定义:它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的改变,不会影响到使用算法的用户。

|
|
database.sql
这里是 1.19.4
|
|
-
策略接口
首先可以明确 database/sql 是类 SQL 数据库都可以调用的,其中 driver 文件下的 driver.go 定义了很多接口,相当于策略接口。
-
Serve 类
database/sql/sql.go 里面的 DB 结构体,相当于上面的 Serve 类。
-
Strategy 类
database/sql/sql.go 里面有
map[string]driver.Driver
,相当与 Strategy 策略类。1 2 3 4 5
// sql 包变量 var ( driversMu sync.RWMutex drivers = make(map[string]driver.Driver) )
-
Algorithm 类
github.com/go-sql-driver/mysql 相当于具体的算法类。里面实现了 database/sql driver.go 的所有接口。
接下来我们追下上面代码的流程:
-
_ "github.com/go-sql-driver/mysql"
mysql 通过匿名引入的方法,引入时会调用包里的
init()
函数如下:1 2 3 4 5 6 7 8 9 10 11 12
// github.com/go-sql-driver/mysql driver.go func init() { // 注意:调用的是 sql 包 sql.Register("mysql", &MySQLDriver{}) } // database/sql sql.go func Register(name string, driver driver.Driver) { driversMu.Lock() defer driversMu.Unlock() drivers[name] = driver }
实际这里就是所谓的注册 MySQL 的驱动,就是策略模式里面的设置具体算法的步骤。
-
db, _ = sql.Open("mysql", dsn)
这里 open 函数并不会真正地与数据库建立连接,而是检查 database/sql 里面的包变量 drivers 有没有 mysql 这个驱动,如果我们上面有通过匿名引入的方式注册 mysql 驱动,那么就不会报错。然后初始化 DB 对象并返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// database/sql sql.go func Open(driverName, dataSourceName string) (*DB, error) { driveri, ok := drivers[driverName] if !ok { return nil, "err" } return OpenDB(dsnConnector{dsn: dataSourceName, driver: driveri}), nil } func OpenDB(c driver.Connector) *DB { db := &DB{ connector: c, openerCh: make(chan struct{}, connectionRequestQueueSize), lastPut: make(map[*driverConn]string), connRequests: make(map[uint64]chan connRequest), stop: cancel, } return db }
-
db.Ping()
Ping 验证与数据库的连接是否仍处于活动状态,如有必要,建立连接。
db.Ping()
以及如果调用db.Query("select * from demo")
其实都是内部真正执行的是db.driver.ping()
或者db.driver.query()
。如果所有代码都写好了,想更改数据库,只需要更改引入的数据库类型,也就是更改注册的数据库驱动的类型即可。实现了解耦。