golang sql源码学习记录

sql

总结

golang只实现了框架,用于如何连接数据库,具体的数据库连接的驱动,由各类数据库实现,如postgresql为pg,mysql为mysql,整体实现为driver目录下定义各种接口,接口定义得比较细致,可能一个函数就对应一个接口,sql目录下实现整体框架,DB结构体为整体入口,Open函数会创建DB,使用DB调用各类操作函数

接口

接口定义在driver目录下

  • driver.Driver,具体驱动实现该接口
    • Open(name string) (Conn, error), 用于新开一个连接
  • driver.DriverContext
    • OpenConnector(name string) (Connector, error),用于新开一个Connector
  • driver.Connector
    • Connect(context.Context) (Conn, error), 用于新开一个Conn
    • Driver() Driver 返回Connector对应的Driver
    • struct dsnConnect为Connector接口的默认实现
  • driver.Conn
    • Prepare(query string) (Stmt, error)
    • Close() error
    • Begin() (Tx, error)
  • driver.Stmt,具体数据库操作实现的接口
    • Close() error,关闭statement
    • NumInput() int,返回参数个数
    • Exec(args []Value) (Result, error),该接口已经Deprecated,Driver应该实现StmtExecContext
    • Query(args []Value) (Rows, error),该接口已经Deprecated,Driver应该实现StmtQueryContext
  • driver.Tx
    • Commit() error,事务提交
    • Rollback() error,事务回滚
  • driver.Pinger,发送ping消息,保持连接存活
    • Ping(ctx context.Context) error
  • driver.Execer,定义Exec的接口
    • Exec
  • driver.ExecerContext
    • ExecContext(ctx context.Context, query string, args []NamedValue) (Result, error)
  • driver.Queryer, 查询接口定义,已经Deprecated
    • Query(Query string, args []Value) (Rows, error)
  • driver.QueryerContext
    • QueryContext(ctx context.Context, query string, args []NamedValue) (Rows, error)
  • driver.ConnPrepareContext
    • PrepareContext(ctx context.Context. query string) (stmt, error)
  • Driver.ConnBeginTx
    • BeginTx(ctx context.Context, opts TxOptions) (Tx, error)
  • SessionResetter,重设连接的session
    • ResetSession

框架实现函数

  • sql.Open函数
    • 从drivers里面获取注册的驱动,如果没有返回err
    • 如果对应的驱动实现了driver.DriverContext接口,然后调用该接口获取Connector,最后调用OpenDB函数
    • 如果没有实现,使用默认实现的dsnConnector,最后调用OpenDB
  • sql.Register函数,各个驱动注册自己的driver.Driver实现到drivers(map存储),如果重复,会panic
  • OpenDB函数,返回sql.DB结构体,主要启动一个后台deamon,用于管理connection
    • 生成待cancel的context,cancel放到sql.DB中
    • context传入connectionOpener,并且通过go异步出去,这个是个connection的deamon,用于在出现错误的时候,新建connection
      • connectionOpener是一个for循环,通过ctx.Done退出循环
      • 通过openerCh来触发openNewConnection
      • openerCh的输入方为maybeOpenNewConnections函数,如果numRequests(请求数)大于0,则新建一个
    • openNewConnection
      • 通过connector新建一个Connector ci
      • 把新建的ci放到driverConn里,如果connRequests大于0,通过从connRequests(map[uint64] chan connRequest)的随机获取一个chan,把driverConn给对应的请求
      • 如果没有请求,则放到freeConn里面去,如果没有超过maxIDleConns
  • sql.DB里的具体函数实现,用于数据库请求
    • PrepareContext函数,Prepare函数调用PrepareContext,返回Stmt
      • 会重试,大小为maxBadConnRetries(值为2)
      • 调用prepare->conn->prepareDC
    • prepare函数
      • 调用conn函数-> prepareDC函数
    • conn函数,返回driverConn,跟openNewConnection实现类似
      • 判断当前DB是否已经被关闭
      • 如果strategy是cachedOrNewConn,且freeConn里面还有空闲conn,则直接使用,如果获取的conn已经过期了,直接返回driver.ErrBadConn
      • 如果maxOpen大于0,且当前打开的numOpen不小于maxOpen,则新建一个connRequest,放到connRequests里去,然后等待putConnDBLocked里往chan里写入connRequest
      • 下面是创建的场景,connector调用Connect函数,返回Connector ci,然后封装到driverConn里面,并放到Dep里面去
    • prepareDC,将query、driverConn、release封装到Stmt(支持并发,底层绑定的是同一个connection)
      • 里层调用ctxDriverPrepare函数,返回driverStmt
        • 如果driver.Conn实现了driver.ConnPrepareContext函数,则调用该PrepareContext函数
        • 如果没有实现,则调用Conn的Prepare函数
      • 将driverStmt、db、query等封装到Stmt里
    • ExecContext,有retry,默认2次,执行exec函数
    • exec
      • 先调用conn函数,获取driverConn
      • 调用execDC函数
    • execDC
      • 如果driverConn.ci Connector实现了ExecerContext,或者driver.Execer,则调用对应的函数
      • 如果没有实现,则调用ctxDriverPrepare函数和resultFromStatement,大体跟上面差不多
    • QueryContext,执行查询,上面exec,sql都执行,tx除外,几种类型的命名风格都类似,先调用conn,然后执行*DC
      • query函数实现,先调用conn获取连接
      • 再调用queryDC
    • queryDC函数
      • 看Connector是否实现dirver.QueryerContext或者Queryer接口,如果是,直接调用对应的实现
      • 没有实现,则是默认实现,调用ctxDriverPrepare和rowsiFromStatement返回结果
    • BeginTx
      • 失败会重试1次
      • 调用begin函数
    • begin,开始事务
      • conn,获取driverConn
      • 调用beginDC,返回sql.Tx
        • driverConn的ci(Conn)实现了ConnBeginTx,则调用对应的实现
        • 否则调用Begin函数
    • Driver函数,返回DB存的Driver
  • Conn结构体,集成到DB中,DB的Conn函数,返回一个可用的Conn
    • PingContext函数,调用DB的pingDC函数,发送ping命令,实则为Pinger接口,具体为各个数据库驱动实现
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值