Golang访问SQL Like数据库(三)——sql package + Postgres driver源码走读
来源:互联网 发布:adobe 软件 编辑:程序博客网 时间:2024/06/03 07:44
github.com/lib/pq
pg是一个纯Go写的Postgres数据库的driver。尼玛,作者给大家开了一个小小的玩笑,pq老是会习惯性的写成pg有没有…安装方式如下:
go get github.com/lib/pq
Register
如前所述,Driver需要调用sql.Register根据名字将driver实现的driver.Driver类型interface注册。pq driver的init函数在源码pq/conn.go文件中,init函数调用sql.Register将driver 数据结构注册到名字”postgres“下。
type drv struct{}func (d *drv)Open(name string)(dirver.Conn, error) { return Open(name)}func init() { sql.Register("postgres", &drv{})}
这样在代码中import ”github.com/lib/pq”时postgres将自动被注册。
下面将以一次Query操作来讲解代码流程。
Sample
首先来一段示例代码(注:代码为伪代码,仅表示流程,不能编译执行):
package mainimport ( "database/sql" _ "github.com/lib/pq")func main() { db, err := sql.Open("postgres", "postgres://user:pwd@server/database?sslmode=disable") rows, err := db.Query("select * from table") stmt, err := db.Prepare("update table set name=$1 where id=$2") res, err := stmt.Exec("xiaoming", 2)}
sql package到driver到sql
前面提到一次数据库操作流程为:
用户代码 --> Sql package -->sql/driver -> database driver -> sql
import包,注册driver
上面示例中首先import了sql package和pq包。在import pq时指定包别名为”_”表示,我们只是需要通过import pq包自动调用包的init函数注册driver,而不需要直接使用包的任何接口。
sql.Register函数在sql/sql.go文件中,代码如下,Register将driver注册到一个全局的Map[string]driver.Driver中。
var ( driversMu sync.RWMutex drivers = make(map[string]driver.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}
User Code –> Sql package -> driver
sql.Open -> db.connectionOpener -> db.openNewConnection
Open首先通过driverName从drivers中查找driver,找到后创建一个DB数据类型,并使用driver赋值给db.driver, dataSourceName赋值给db.dsn初始化新的DB。
然后db.Open调用db.connectionOpener, db.connectionOpener将便利所有的channel,并执行db.openNewConnection.
db.openNewConnection将调用db.driver.Open(即pq.drv.Open)对dataSourceName进行验证,如果dataSourceName中的参数遵循正确的格式,且有足够多可可以用于连接数据库的参数则返回一个driver.Conn接口。
pq中的代码主要流程为:
drv.Open -> Open -> DialOpen
db.openNewConnection在获得driver.Open返回的driver.Conn后将为其包装一个mutex防止对driver.Conn interface的并发调用相互影响。
User Code ->Sql package -> driver -> Sql
上面示例代码中分别对数据库执行了两次完整的操作,一次是Query操作,还有一次是Update操作。本文仅对Query流程进行讲解,Update流程类似,读者可自行追代码了解。
sql中的Query的主要流程为:
sql.DB.Query | -> sql.DB.query | -> sql.DB.queryConn | -> driver.Conn.Prepare (dirver) | -> rowsiFromStatement | -> driver.Stmt.Query (driver)
Query主要进行连接retry次数的控制,然后调用query执行实际的Query操作。
query首先根据连接类型(默认cachedOrNewConn)从连接池中获取前面Open返回的driver.Conn interface. 如果有相应连接,则调用queryConn执行Query操作。
queryConn在执行一些验证、上锁操作等候,掉用driver。Conn的Prepare准备statement。这里的流程已经成功无缝切到driver部分。在driver层由Prepare函数完成statement准备后,控制权再次返回到sql package中。获取statement类型Stmt后,同样是封装一层后,调用rowsiFromStatement。
rowsiFromStatement进行了一些互斥上锁操作后,通过调用Stmt.Query再次切换到driver层,通过driver具体实现的Query函数对数据库进行操作,读取Rows并返回。
pq中Conn实现的Prepare部分源码如下:
func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) { if cn.bad { return nil, driver.ErrBadConn } defer cn.errRecover(&err) if len(q) >= 4 && strings.EqualFold(q[:4], "COPY") { return cn.prepareCopyIn(q) } return cn.prepareTo(q, cn.gname()), nil}
pq中Stmt实现的Query部分源码如下:
func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) { if st.cn.bad { return nil, driver.ErrBadConn } defer st.cn.errRecover(&err) st.exec(v) return &rows{ cn: st.cn, colNames: st.colNames, colTyps: st.colTyps, colFmts: st.colFmts, }, nil}
参考链接
https://golang.org/src/database/sql/doc.txt
https://godoc.org/database/sql
https://golang.org/src/database/sql/
https://godoc.org/github.com/lib/pq
https://github.com/lib/pq
https://godoc.org/github.com/lib/pq
http://jmoiron.github.io/sqlx/
https://github.com/jmoiron/sqlx/blob/master/sqlx.go
https://github.com/golang/go/wiki/SQLInterface
https://github.com/golang/go/wiki/SQLDrivers
- Golang访问SQL Like数据库(三)——sql package + Postgres driver源码走读
- Golang访问SQL like数据库(二)——sql package主要数据结构及方法
- Golang访问SQL like数据库(一)——思想、driver需实现接口
- 数据库中间件 Sharding-JDBC 源码分析 —— SQL 解析(三)之查询SQL
- postgres 数据库常用sql语句
- postgres数据库sql语句汇总
- 数据库——SQL中like与通配符的使用
- Spark源码走读(三) —— Stage的划分和提交
- Sql UNION ALL 应用实例(Postgres数据库)
- spark sql + postgres 实现数据库计算
- SQL (like) 使用
- Spark源码走读之 -- sql的解析与执行
- 高效访问数据库—SQL语言技术
- Python中SQL——LIKE中的%
- sql like
- sql like
- sql like
- SQL LIkE
- 占位
- spring 配置加载外部文件的两种方式
- 博客积分新捷径
- Golang访问SQL like数据库(二)——sql package主要数据结构及方法
- YUV422/YUV420
- Golang访问SQL Like数据库(三)——sql package + Postgres driver源码走读
- 空间这个日志 没有 排名的。
- [DP]Adapter设计模式
- 1083. List Grades (25)-PAT甲级真题
- activesupport requires Ruby version >= 2.2.2
- 欢迎使用CSDN-markdown编辑器
- 题解Find K Pairs with Smallest Sums
- PHP获取图片主要颜色RGB代码
- python 2016.8.8 python小游戏— —猜数字