当前位置: 首页 > news >正文

做购实惠网站的意义武汉seo 网络推广

做购实惠网站的意义,武汉seo 网络推广,网站建设搜索,php动态网站开发实训报告文章目录 前言一、go-sql-driver/mysql1、驱动注册:sql.Register2、驱动实现:MysqlDriver3、RegisterDialContext 二、总结 前言 在上篇文章中我们知道,database/sql只是提供了驱动相关的接口,并没有相关的具体实现,具…

文章目录

    • 前言
    • 一、go-sql-driver/mysql
      • 1、驱动注册:sql.Register
      • 2、驱动实现:MysqlDriver
      • 3、RegisterDialContext
    • 二、总结

前言

在上篇文章中我们知道,database/sql只是提供了驱动相关的接口,并没有相关的具体实现,具体内容是由第三方实现的,如go-sql-driver/mysql:https://github.com/go-sql-driver/mysql/,本章中我们主要是探究这个驱动实现库的具体实现。以及它是如何与database/sql一起作用的。

一、go-sql-driver/mysql

go-sql-driver作为一个三方驱动库,主要就是实现database/sql中的驱动接口了,因此,主要的文件也就是driver.go、connector.go和connection.go几个文件了。因此,本章的阅读业主要聚焦与这三个文件中的源码内容。
在这里插入图片描述

1、驱动注册:sql.Register

通常,我们都会这样调用database/sql的Open方法创建一个db实例:

import ("database/sql"_ "github.com/go-sql-driver/mysql"
)// ...db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {panic(err)
}

初看是不是觉得很奇怪,在这段代码中,我们没有直接使用到go-sql-driver的的任何东西,但却需要引入这个包,这是因为,sql.Open方法中,我们知道,会检查获取对应的驱动,而驱动的注册是由第三方驱动实现包调用Register方法完成的。

在go-sql-driver中的driver.go中,我们发现init函数中会调用Register方法注册相应的驱动,这也是上面的代码中为什么需要引入这个包的原因。

func init() {if driverName != "" {sql.Register(driverName, &MySQLDriver{})}
}

2、驱动实现:MysqlDriver

在go-sql-driver中,核心的driver.go中实现了具体的mysql驱动(MysqlDriver)

// Open new Connection.
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
// the DSN string is formatted
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {cfg, err := ParseDSN(dsn)if err != nil {return nil, err}c := newConnector(cfg)return c.Connect(context.Background())
}

在该方法中,首先从数据源dsn中解析出对应的配置,然后再构造对应的连接器,调用连接器的Connect方法与mysql建立连接。

connector实现了driver.Connector接口,其中Connect方法主要是与mysql进行交互,包括:拨号(dial)、认证、利用mysql协议发包与收包处理结果等,

type connector struct {cfg               *Config // immutable private copy.encodedAttributes string  // Encoded connection attributes.
}func newConnector(cfg *Config) *connector {encodedAttributes := encodeConnectionAttributes(cfg)return &connector{cfg:               cfg,encodedAttributes: encodedAttributes,}
}// Connect implements driver.Connector interface.
// Connect returns a connection to the database.
func (c *connector) Connect(ctx context.Context) (driver.Conn, error) {var err error// Invoke beforeConnect if present, with a copy of the configurationcfg := c.cfgif c.cfg.beforeConnect != nil {cfg = c.cfg.Clone()err = c.cfg.beforeConnect(ctx, cfg)if err != nil {return nil, err}}// New mysqlConnmc := &mysqlConn{maxAllowedPacket: maxPacketSize,maxWriteSize:     maxPacketSize - 1,closech:          make(chan struct{}),cfg:              cfg,connector:        c,}mc.parseTime = mc.cfg.ParseTime// Connect to ServerdialsLock.RLock()dial, ok := dials[mc.cfg.Net]dialsLock.RUnlock()if ok {dctx := ctxif mc.cfg.Timeout > 0 {var cancel context.CancelFuncdctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout)defer cancel()}mc.netConn, err = dial(dctx, mc.cfg.Addr)} else {nd := net.Dialer{Timeout: mc.cfg.Timeout}mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr)}if err != nil {return nil, err}mc.rawConn = mc.netConn// Enable TCP Keepalives on TCP connectionsif tc, ok := mc.netConn.(*net.TCPConn); ok {if err := tc.SetKeepAlive(true); err != nil {c.cfg.Logger.Print(err)}}// Call startWatcher for context support (From Go 1.8)mc.startWatcher()if err := mc.watchCancel(ctx); err != nil {mc.cleanup()return nil, err}defer mc.finish()mc.buf = newBuffer(mc.netConn)// Set I/O timeoutsmc.buf.timeout = mc.cfg.ReadTimeoutmc.writeTimeout = mc.cfg.WriteTimeout// Reading Handshake Initialization PacketauthData, plugin, err := mc.readHandshakePacket()if err != nil {mc.cleanup()return nil, err}if plugin == "" {plugin = defaultAuthPlugin}// Send Client Authentication PacketauthResp, err := mc.auth(authData, plugin)if err != nil {// try the default auth plugin, if using the requested plugin failedc.cfg.Logger.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())plugin = defaultAuthPluginauthResp, err = mc.auth(authData, plugin)if err != nil {mc.cleanup()return nil, err}}if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {mc.cleanup()return nil, err}// Handle response to auth packet, switch methods if possibleif err = mc.handleAuthResult(authData, plugin); err != nil {// Authentication failed and MySQL has already closed the connection// (https://dev.mysql.com/doc/internals/en/authentication-fails.html).// Do not send COM_QUIT, just cleanup and return the error.mc.cleanup()return nil, err}if mc.cfg.MaxAllowedPacket > 0 {mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket} else {// Get max allowed packet sizemaxap, err := mc.getSystemVar("max_allowed_packet")if err != nil {mc.Close()return nil, err}mc.maxAllowedPacket = stringToInt(maxap) - 1}if mc.maxAllowedPacket < maxPacketSize {mc.maxWriteSize = mc.maxAllowedPacket}// Handle DSN Paramserr = mc.handleParams()if err != nil {mc.Close()return nil, err}return mc, nil
}// Driver implements driver.Connector interface.
// Driver returns &MySQLDriver{}.
func (c *connector) Driver() driver.Driver {return &MySQLDriver{}
}

同时,我们还注意到,Connect方法中调用了一个startWatcher方法,该方法从watcher通道中接收一个ctx,并对这个ctx进行监听,每次都会调用一个watchCancel方法将ctx传递Watcher,watcher监听到ctx.Done的信号后,将会调用cancel方法,启动清理工作。

func (mc *mysqlConn) startWatcher() {watcher := make(chan context.Context, 1)mc.watcher = watcherfinished := make(chan struct{})mc.finished = finishedgo func() {for {var ctx context.Contextselect {case ctx = <-watcher:case <-mc.closech:return}select {case <-ctx.Done():mc.cancel(ctx.Err())case <-finished:case <-mc.closech:return}}}()
}

cancel方法将会调用cleanup方法进行连接的清理工作,可以看到在cleanup中调用了conn.Close,将这个物理连接关闭掉。因此,我们在使用QueryContext或者ExecContext时候,如果ctx设置了超时时间,或者主动cancel,那么意味着这个连接将会被断掉。极端情况下,大量连接同时超时,意味着连接都将失效,此时再有新的请求打进来则会重新建立新的连接,会有一定的连接建立开销。由于连接池是database/sql维护的,因此这也只是客户端(或者说mysql sdk)层面的失效,mysql server接收到的sql执行是不会被中断的。

// finish is called when the query has canceled.
func (mc *mysqlConn) cancel(err error) {mc.canceled.Set(err)mc.cleanup()
}// Closes the network connection and unsets internal variables. Do not call this
// function after successfully authentication, call Close instead. This function
// is called before auth or on auth failure because MySQL will have already
// closed the network connection.
func (mc *mysqlConn) cleanup() {if mc.closed.Swap(true) {return}// Makes cleanup idempotentclose(mc.closech)conn := mc.rawConnif conn == nil {return}if err := conn.Close(); err != nil {mc.log(err)}// This function can be called from multiple goroutines.// So we can not mc.clearResult() here.// Caller should do it if they are in safe goroutine.
}

在实际项目中,为了减少使用层面的超时导致连接失效这种情况,我们也可以对mysql server设置一个wait_timeout时间,并且调用QueryContext/ExecContext的超时时间要小于这个wait_timeout时间,这样则不会由于某业务中有慢查的sql,导致ctx超时,从而频繁触发连接的重新建立。

3、RegisterDialContext

最后我们再看看下这个静态方法:RegisterDialContext,这个方法主要作用就是注册对应的协议的dialFunc,便于在进行数据库连接时候找到真正的地址。

// RegisterDialContext registers a custom dial function. It can then be used by the
// network address mynet(addr), where mynet is the registered new network.
// The current context for the connection and its address is passed to the dial function.
func RegisterDialContext(net string, dial DialContextFunc) {dialsLock.Lock()defer dialsLock.Unlock()if dials == nil {dials = make(map[string]DialContextFunc)}dials[net] = dial
}// DialContextFunc is a function which can be used to establish the network connection.
// Custom dial functions must be registered with RegisterDialContext
type DialContextFunc func(ctx context.Context, addr string) (net.Conn, error)

二、总结

本篇文章我们看了go-sql-driver的具体实现,整体上来说,go-sql-driver都是实现database/sql的driver.Driver接口,直接对接mysql服务端,支持mysql协议的收发包,在api层面,query/exec两个方法都提供了带ctx的方法,带ctx和不带ctx的api使用差异,一点小小的切换可能导致不断频繁建立连接与关闭连接等,最后我们也根据实际的情况提出解决此问题的方案。


文章转载自:
http://decide.c7495.cn
http://echinite.c7495.cn
http://hairnet.c7495.cn
http://crosswind.c7495.cn
http://gamomania.c7495.cn
http://jugoslav.c7495.cn
http://ineffectually.c7495.cn
http://knuckleball.c7495.cn
http://mantoux.c7495.cn
http://gesticulation.c7495.cn
http://photoreaction.c7495.cn
http://worrit.c7495.cn
http://pelops.c7495.cn
http://remaindership.c7495.cn
http://parasexual.c7495.cn
http://edmond.c7495.cn
http://genesis.c7495.cn
http://adiaphorous.c7495.cn
http://changeable.c7495.cn
http://kufa.c7495.cn
http://staffer.c7495.cn
http://epitope.c7495.cn
http://variational.c7495.cn
http://nightwear.c7495.cn
http://micrometry.c7495.cn
http://nannie.c7495.cn
http://innutrition.c7495.cn
http://ephyra.c7495.cn
http://hostility.c7495.cn
http://inscience.c7495.cn
http://cyanogenic.c7495.cn
http://patriclinous.c7495.cn
http://groovelike.c7495.cn
http://lionlike.c7495.cn
http://leigh.c7495.cn
http://stolen.c7495.cn
http://ferrocyanide.c7495.cn
http://bullboat.c7495.cn
http://jubbulpore.c7495.cn
http://paisan.c7495.cn
http://eggwalk.c7495.cn
http://brickfielder.c7495.cn
http://masterwork.c7495.cn
http://sarcomatosis.c7495.cn
http://carpetbagger.c7495.cn
http://amyloid.c7495.cn
http://io.c7495.cn
http://poi.c7495.cn
http://mnemotechny.c7495.cn
http://whether.c7495.cn
http://piedmontite.c7495.cn
http://quislism.c7495.cn
http://do.c7495.cn
http://hamfooted.c7495.cn
http://adjust.c7495.cn
http://weediness.c7495.cn
http://apivorous.c7495.cn
http://diachronic.c7495.cn
http://hyperspace.c7495.cn
http://praiseworthily.c7495.cn
http://johannes.c7495.cn
http://tenty.c7495.cn
http://accrescent.c7495.cn
http://chromaticity.c7495.cn
http://sene.c7495.cn
http://theban.c7495.cn
http://pedler.c7495.cn
http://shapoo.c7495.cn
http://sequoia.c7495.cn
http://emile.c7495.cn
http://cogitator.c7495.cn
http://deacidify.c7495.cn
http://nabeshima.c7495.cn
http://however.c7495.cn
http://regenerative.c7495.cn
http://tardiness.c7495.cn
http://gorm.c7495.cn
http://demonocracy.c7495.cn
http://preservative.c7495.cn
http://libriform.c7495.cn
http://sideway.c7495.cn
http://consort.c7495.cn
http://utilization.c7495.cn
http://catechu.c7495.cn
http://conk.c7495.cn
http://towline.c7495.cn
http://solicitor.c7495.cn
http://pauper.c7495.cn
http://atempo.c7495.cn
http://geomorphology.c7495.cn
http://victorianize.c7495.cn
http://obconical.c7495.cn
http://unpathed.c7495.cn
http://ani.c7495.cn
http://prolegomena.c7495.cn
http://absinth.c7495.cn
http://bedstone.c7495.cn
http://saddlebag.c7495.cn
http://oaken.c7495.cn
http://foumart.c7495.cn
http://www.zhongyajixie.com/news/67548.html

相关文章:

  • 做电影网站需要营销型网站定制
  • 提升网站权重吗上海最新新闻
  • 营销案例最新抚州网站seo
  • 订单查询网站怎么做企业网站建设的步骤
  • 南通公司网站制作以品牌推广为目的的广告网络平台
  • edu域名网站2023网站分享
  • 初级前端工程师工资谷歌seo推广培训班
  • 网站开发和网站维护有区别吗在什么网站可以免费
  • 佛山网站建设开发长沙网站定制
  • web网站开发德 参考文献中央刚刚宣布大消息
  • 区校合作网站建设方案抖音seo排名系统
  • 国外做蒸汽锅炉的网站网盘app下载
  • 企业建站公司实力对比广东队对阵广州队
  • 我做的网站不能往下拉模板之家
  • wordpress 相互关注seo关键词分析表
  • 做水果苹果大的网站seo推广官网
  • 进空间的网站东莞企业推广网站制作
  • Dedecms手机网站源码软文推广案例
  • 是不是做推广都得有网站seo关键词快速获得排名
  • 网站链接交换百度关键词如何优化
  • 做网站项目的心得如何进行网络营销推广
  • 做网站彩票代理犯法吗今天全国疫情最新消息
  • 网站活动推广方案免费的编程自学网站
  • 万网域名网站建设小程序制作费用一览表
  • 烟台市建设工程检测站网站怎样注册网站免费注册
  • 有哪些高端的网站整站优化深圳
  • 贵州 政府网站建设规范百度首页快速排名系统
  • 广州做网站星珀百度搜索网站排名
  • 用哪个网站做首页好济南最新消息
  • wordpress文章到qq群seo教程自学