热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Golang访问SQLLike数据库(三)——sqlpackage+Postgresdriver源码走读

github.comlibpqpg是一个纯Go写的Postgres数据库的driver。尼玛,作者给大家开了一个小小的玩笑,pq老是会习惯性的写成pg有没有…安装方式如下:gog

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 main

import (
"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


推荐阅读
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 代理模式的详细介绍及应用场景
    代理模式是一种在软件开发中常用的设计模式,通过在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象进行访问,从而简化系统的复杂性。代理模式可以根据不同的使用目的分为远程代理、虚拟代理、Copy-on-Write代理、保护代理、防火墙代理、智能引用代理和Cache代理等几种。本文将详细介绍代理模式的原理和应用场景。 ... [详细]
  • 本文介绍了在Ubuntu系统中清理残余配置文件和无用内容的方法,包括清理残余配置文件、清理下载缓存包、清理不再需要的包、清理无用的语言文件和清理无用的翻译内容。通过这些清理操作可以节省硬盘空间,提高系统的运行效率。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • centos php部署到nginx 404_NodeJS项目部署到阿里云ECS服务器全程详解
    本文转载自:http:www.kovli.com20170919ecs-deploy作者:Kovli本文详细介绍如何部署NodeJS项目到阿里云ECS上, ... [详细]
  • charles3.11.1抓https包
    结论先行:用的是安卓测试机,没加固之前的生产环境的安装包,可以抓到https请求加固之后的包【也就是要上应用市场的包】,抓不到https请求电脑上的操作:1.安装证书【电脑上安装了 ... [详细]
  • tomcat的log文件夹下有以下几种日志:1、catalina.YYYY-MM-DD.logcatalina引擎输出的日志;catalina是tomc ... [详细]
  • OAuth2.0指南
    引言OAuth2.0是一种应用之间彼此访问数据的开源授权协议。比如,一个游戏应用可以访问Facebook的用户数据,或者一个基于地理的应用可以访问Foursquare的用户数据等。 ... [详细]
author-avatar
itbases
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有