Go源码分析系列:sql驱动加载

Go源码分析系列:sql驱动加载,第1张

概述对于开发人员来说,我们不仅要知其然,更要知其所以然,不仅要知道工具如何用,更要知道,工具的原理,这也是我写这个文章系列(Go源码分析)的意义,记录的同时,也希望对大家有所帮助。话不多说,直接开始:------------------------------- 先说一下go语言中提供的一个sql框架(database/sql),但是

对于开发人员来说,我们不仅要知其然,更要知其所以然,不仅要知道工具如何用,更要知道,工具的原理,这也是我写这个文章系列(Go源码分析)的意义,记录的同时,也希望对大家有所帮助。

话不多说,直接开始:

-------------------------------

 

先说一下go语言中提供的一个sql框架(database/sql),但是呢,它只提供了一个架子,并没有具体实现,我们可以通过插件的方式注册自己想要使用的数据库,比如MysqL。

下面看一段代码:

package mainimport (	"database/sql"	"fmt"	_ "github.com/go-sql-driver/MysqL")var db *sql.DB // 连接池对象func initDB() (err error) {	dsn := "user:pwd@tcp(ip:port)/db" // 用户名:密码@tcp(IP:端口)/数据库名	db, err = sql.Open("MysqL", dsn) // 只会校验格式	if err != nil {		fmt.Printf("dsn:%s invalID, err = %v\n", dsn, err)		return	}	err = db.Ping() // 连接服务器校验登录信息	if err != nil {		fmt.Printf("open:%s Failed, err = %v\n", dsn, err)		return	}	fmt.Printf("open:%s success\n", dsn)	return}

代码很简单,就是建立一个MysqL的数据库连接池对象,这段代码里面最重要的就是这一行代码:

import (	_ "github.com/go-sql-driver/MysqL")

如果不加这一句,在“sql.Open("MysqL", dsn)”的时候,就会告知你没有MysqL的驱动,看一下“sql.Open”的源码就知道原因了:

package sqlvar (	...	drivers   = make(map[string]driver.Driver))func Register(name string, driver driver.Driver) {	...	drivers[name] = driver}func Open(drivername, dataSourcename string) (*DB, error) {	...	driveri, ok := drivers[drivername]	...	return OpenDB(dsnConnector{dsn: dataSourcename, driver: driveri}), nil}

drivers默认是空的,也就是说,只能通过Register注册驱动后,才能使用,这就是关键点了。

为什么要导“github.com/go-sql-driver/MysqL”包,MysqL包下的driver.go做的就是初始化注册驱动的 *** 作:

package MysqLfunc init() {	sql.Register("MysqL", &MysqLDriver{})}

这也就解释了,为什么不导包,“sql.Open("MysqL", dsn)”就会报错,也能充分体现出插件化的灵活性。

 

如果大家有兴趣,我再多说一点关于数据库连接池的知识点,看下调用的代码:

func main() {	err := initDB()	if err != nil {		fmt.Printf("init db Failed, err = %v\n", err)		return	}	defer db.Close()	var u user	sql := `select ID,name from user where ID=?;`	row := db.queryRow(sql, 2)	err = row.Scan(&u.ID, &u.name)	if err != nil {		fmt.Printf("Scan Failed, err = %v\n", err)		return	}	fmt.Printf("Scan success, u = %v\n", u)}

关键代码在“db.queryRow”和“row.Scan”这两行,在“db.queryRow”之后,如果没有调用“row.Scan”,连接池就会处于一个保持连接的状态,占用资源,达到一定数量线程将会阻塞,看一下“row.Scan”中的代码实现就明白了:

func (r *Row) Scan(dest ...interface{}) error {	...	defer r.rows.Close()	...}

Scan *** 作将会关闭当前queryRow建立的连接池,所以,为了避免此情况,也有很多人会采用以下写法:

db.queryRow(sql, 2).Scan(&u.ID, &u.name)

至于连接池的大小,可以通过以下方式设置(一般放在初始化的时候):

db.SetMaxOpenConns(10) 

本次分享就到这里,如果您有问题或者其他建议,欢迎留言讨论。

 

 

------------

作者寄语:

我们缺乏的常常不是编码能力,而是思考能力。
既然热爱编程,那就静下心来,要知道,每一个台阶,都可以是终点,也可以是新的起点。

 

 

总结

以上是内存溢出为你收集整理的Go源码分析系列:sql驱动加载全部内容,希望文章能够帮你解决Go源码分析系列:sql驱动加载所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1244623.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存