This is a creation in Article, where the information may have evolved or changed. #sql. stmt is a visible entity that the SQL package exposes to program callers, typically through DB. The next step after the open function obtains the DB instance is to invoke the stmt of the Func (db *db) Prepare method
#其内部通过 CSS []connstmt to bind the associated connection and drive layer driver. Stmt
#其内部不是引用driverConn, instead of referencing a CSS []connstmt
#sql包中有两个方式能够创建Stmt实例, one is DB Prepare () one is TX Prepare (), the two are different
#Tx创建的Stmt通过Tx关联的driverConn绑定到固定的网络连接上
#DB创建的Stmt时初始化过程
1. An idle connection is taken from the connection pool, and a connstmt instance is created and added to the stmt CSS Slice
2. The creation process is to call the conn of the DB to get an available Driverconn instance and then call Driverconn's driver. Conn Prepare () creates the driver. stmt instance, add the instance to Driverconn's openstmt map and mark it.
3. Initialize the acquired Driverconn instance and driver.stmt instance connstmt, and then add the CSS
#为什么绕一个大圈子, without binding Stmt to death of a driver.conn and a driver.stmt,
#原因是sql包的作者想把Stmt和具体的连接解耦, why decoupling is the reason why stmt can be used for a long time (rather than being created and destroyed frequently), but does not want it to occupy a connection for a long time, resulting in a burst of connections, and increasing the difficulty of connection recycling, This also leads to the problem of creating driver on too many connections. stmt instances, this control is not easy to cause problems with the MySQL server (causing prepared_stmt_count value to burst)
Use of database/sql:stmt and pits
Once a stmt instance is created #拿到 DB, the next time you use it, you need a get connection to rebind driver. Conn and a driver.stmt process.
The Func (S *stmt) connstmt (CI *driverconn, releaseconn func (Error), SI driver are called within the #Stmt的method exec,query. STMT, err Error) function to get
#重新绑定driver. Conn and a driver.stmt instance, this fetching process is unusually tortuous:
1. Determine if the state of the stmt is closed
2. Determine if stmt was created by TX, and if so, get driverconn and driver.stmt back directly from the TX instance
3. Note that the cached connection in the CSS may be closed for a variety of reasons, call removeclosedstmtlocked () to do a cleanup
4. Call the DB instance S.db.conn (cachedornewconn) of the stmt Association to get a connection *driverconn
5. Determine if the Stmt CSS has been cached in the connection, if it has been cached Driverconn instances and driver.stmt have been cached in the CSS, you can directly use
6. If the stmt CSS does not cache the connection, it indicates that the STMT SQL statement was not bound to the connection before. Need to rebind: Create an driver.stmt instance from the Driverconn instance and SQL statement, initialize the CONNSTMT instance, add the CSS, and
Driverconn Instances and Driver.stmt returns
7. Once you have the Driverconn instance and driver.stmt, you can directly invoke the method provided by the driver to process it.
#调用逻辑 # Get driver through drivername, get the original connection to DB via the open () method of driver Func Open (drivername, datasourcename string) (*db, error) = > #生成Stmtfunc (db *db) Prepare (query string) (*stmt, error) = #内部func (db *db) Prepare (query string, strategy Connreus Estrategy) (*stmt, error) = #生成driverConnfunc (db *DB) conn (Strategy Connreusestrategy) (*driverconn, error) = = Func (S *stmt) Exec (args ... interface{}) (Result, error) func (S *stmt) Query (args ... interface{}) (*rows, error) = #有可能使 With prepare, it is also possible to rebind connection func (S *stmt) connstmt (CI *driverconn, releaseconn func (Error), SI driver. STMT, err error) = = #注意这里仅仅是将Stmt实例的状态置为closed, for TX will connect off func (S *stmt) close () error
#第一个连接创立过程
Func Open (drivername, datasourcename string) (*db, error) {475 DB: = &db{476 driver:driveri, 477 Dsn:datasourcename, 478 Openerch:make (Chan struct{}, Connectionrequestqueuesize), 479 lastput: Make (map[*driverconn]string), 480} Go Db.connectionopener ()} #此时并没有创建连接, just initialize the DB part of the data structure # The simplest ping function to see how the connection establishes the Func (DB *db ) Ping () error {491 DC, err: = Db.conn (Cachedornewconn) 492 If Err! = Nil {493 Retu RN Err 494} 495 Db.putconn (DC, nil)} #conn并不直接创建连接先到db中寻 Find out if there is an idle connection, no then create Driverconn instance func (DB *DB) conn (Strategy Connreusestrategy) (*driverconn, error) {... 708 db.numopen++//optimistically709 Db.mu.Unlock () 710 CI, err: = Db.driver.Open (DB.DSN) 711 If Err! = Nil {712 Db.mu.Lock () 713 db.numopen--//Correct for earlier optimism 714 Db.mu.Unlock () 715 return nil, err 716} 717 Db.mu.Lock () 718 DC: = &driverconn{719 db:db, 720 ci:ci, 721} 722 db.adddeplocked (DC, DC) 723 Dc.inuse = True 724 db.mu.Unlock () 725 return DC, nil} #将使用完的driverConn实例放到db数据结构中func (db *db) Putconn (DC *driverconn, err Error) =>func (db *db) putconndblocked (DC *driverconn, err error) bool #另外sql包启动单独一个goroutine负责创建 Connect Go Db.connectionopener () 633 func (db *db) Connectionopener () {634 for range Db.openerch {635 db.opennew Connection () 636} 637} 639//Open one new Connection 640 func (db *db) Opennewconnection () {641 CI, err: = db . Driver. Open (DB.DSN) 642 Db.mu.Lock () 643 defer db.mu.Unlock () 644 if db.closed {645 if Err = = Nil {646 Ci. Close() 647} 648 return 649} 650 db.pendingopens--651 if err! = Nil {652 Db.putconndblo Cked (nil, err) 653 return 654} 655 DC: = &driverconn{656 db:db, 657 Ci:ci, 658 } 659 if db.putconndblocked (DC, err) {660 db.adddeplocked (DC, DC) 661 db.numopen++ 662} else { 663 CI. Close () 664} 665}
####################################################### #Stmt初始化过程 ############################################## ######### #生成Stmtfunc (db *db) Prepare (query string) (*stmt, error) = #内部调用func (db *db) Prepare (query string, strategy C Onnreusestrategy) (*stmt, error) {#创建driverConndc, err: = Db.conn (strategy) #创建driver. Stmtsi, err: = dc.preparelocked (query) #driverConn和driver. stmt is added to the CSS 878 stmt: = &stmt{ 879 Db:db, 880 Query:query, 881 css: []connstmt{{dc, si}}, 882 lastnumclosed:atomic. LoadUint64 (&db.numclosed),} 883} #Stmt的初始化和执行是分开的, again get Stmt run time need to rebind to Eexc () as an example analysis under Func (S *stmt) Exec (args ... int erface{}) (Result, error) {#The most core connstmt () function gets the binding stmt of the rebinding DC, Releaseconn, si, err: = S.connstmt () #func resultfromstatement (ds driverstmt, args ... interface{}) (Result, error) calls the driver's driver. stmt Execute res, err = resultfromstatement (DRIVERSTMT{DC, si}, args ...)} Func (S *stmt) connstmt () (CI *driverconn, releaseconn func (Error), SI driver. STMT, err Error) {#拿到一个连接 *DRIVERCONNDC, err: = S.db.conn (Cachedornewconn) #查询s. Cached connstmt *driverconn in CSS Whether the connection with the connection pool is the same, if it is the same, the direct return # description stmt instance of SQL has completed prepare initialization, you can directly use the 1453 for _, V: = Range S.css {1454 if v.dc = = DC {1455 S.mu.unlock () 1456 return DC, Dc.releaseconn, v.si, nil1457}1458} #如果新拿到的连接没有 The cache stmt the corresponding SQL DRIVER.STMT data structure # to regenerate the driver. Stmtsi, err = dc.preparelocked (s.query) #创建connStmt实例, insert it into stmt CSS slice cs: = connstmt{dc, si}s.css = append (s.css, CS)}# If the connection pool is too connected, the connection that is taken when stmt executes is initially bound to be very low, which results in one SQL execution being bound once and causing too many connections to stmt CSS bindings. #这个控制内部有个机制来去func (S *stmt) removeclosedstmtlocked ()