This is a creation in Article, where the information may have evolved or changed. Welcome to follow me: [Go source column] (https://zhuanlan.zhihu.com/c_135808959) # # # #gorm的Open函数 "db, err: = Gorm. Open (config. Getdbname (), CONFIG. Getdbsource ()) "' # # # #gorm. Open () "Func open (dialect string, args ... interface{}) (db *db, err error) {var source stringvar dbsql Sqlcommonswitch VA Lue: = Args[0]. (type) {case String:var Driver = Dialectif len (args) = = 1 {fmt. Println ("args[0]:", args[0]) fmt. Println ("Value:", value) Source = value} else if Len (args) >= 2 {driver = Valuesource = Args[1]. ( String)}dbsql, err = sql. Open (driver, source) Case sqlcommon:dbsql = Value}db = &db{db:dbsql,logger:defaultlogger,values:map[string] Interface{}{},callbacks:defaultcallback,dialect:newdialect (dialect, dbsql),}db.parent = dbif Err! = Nil {return}// Send a ping to make sure the database connection is Alive.if d, OK: = Dbsql. (*sql. DB); OK {if Err = d.ping (); Err! = nil {d.close ()}}return} "is first obtained according to the first parameter: an instance of the Sqlcommon interface, sql.db implementation. by calling SQL. Open (driver, source) obtained, or directly passed in. # # # #SQLCommon接口 "//SQLCommon is the minimal database connection functionality Gorm requires. Implemented by *sql. Db.type Sqlcommon Interface {Exec (query string, args ... interface{}) (SQL. Result, error) Prepare (query string) (*sql. STMT, error) Query (query string, args ... interface{}) (*sql. Rows, error) queryrow (query string, args ... interface{}) *sql. Row} ' Sqlcommon is the smallest database connectivity feature. *sql. DB is implemented. (The connection pool that the SQL package implements.) # # # #sql. Open function ' func open (drivername, datasourcename string) (*db, error) {Driversmu.rlock () Driveri, OK: = Drivers[drivername] Driversmu.runlock () If!ok {return nil, fmt. Errorf ("Sql:unknown driver%q (forgotten Import)", drivername)}db: = &db{driver:driveri,dsn:datasourcename, Openerch:make (Chan struct{}, Connectionrequestqueuesize), Lastput:make (map[*driverconn]string), Connrequests:make ( Map[uint64]chan connrequest),}go Db.connectionopener () return db, nil} ' ' First there is a read and write lock. (prevents the read time from being changed) gets MySQL's init () assigned to the drive driver. Then, based on the driver of this drive, we get an instance pointer db of the connection Pool db. Finally open a thread go db.connectionopener (). Return to this db.### #connectionOpener () ''//Runs in a separate goroutine, opens new connections when Requested.func (db *db) Connectionopener () {for range Db.open Erch {db.opennewconnection ()}} "in a separate goroutine, open a new connection when needed. This place will always be blocked here, because Db.openerch is a channel, When the data is not placed in the db.openerch, it will always be blocked here. So here must be an independent goroutine, otherwise it will deadlock. Openerch Chan struct{}### #openNewConnection () "//Open one new Connectionfunc (db *db) Opennewconnection () {//maybeopennewconnctions have already executed db.numopen++ before it sent//on Db.openerch. This function must the Execute db.numopen--if the//connection fails or is closed before returning.ci, err: = Db.driver.Open ( DB.DSN) Db.mu.Lock () defer db.mu.Unlock () if db.closed {if Err = = Nil {ci. Close ()}db.numopen--return}if err! = Nil {db.numopen--db.putconndblocked (nil, err) db.maybeopennewconnections () RETURN}DC: = &driverconn{db:db,createdat:nowfunc (), Ci:ci,}if db.putconndblocked (DC, err) {db.addDepLocked (DC, DC } else {db.numopen--ci.close ()} ' "This opens a new connection function that is actually establishing a database connection, and is connected by the first registered such as MySQL driver. returnBack to a database connection Conn. and since Conn is stateful and cannot be shared by multiple goroutine, each goroutine will open a conn for itself and save it as follows: = &driverconn{db:db, Createdat:nowfunc (), Ci:ci,} This saves the shared connection pool db and the unique connection CI in a new connection Driverconn (contains the lock?) Inside, and then putconndblocked### #putConnDBLocked (DC *driverconn, err Error) The main function is to either satisfy a connection request or put a connection into an idle connection pool to return true, otherwise false "' Func (db *db) putconndblocked (DC *driverconn, err Error) bool {if db.closed {return false}if db.maxopen > 0 && Db.numopen > Db.maxopen {return false}if c: = Len (db.connrequests); C > 0 {var req chan Connrequestvar reqkey uint64for reqkey, req = range db.connrequests {break}delete (db.connrequests, Reqkey)//Remove from pending requests.if err = nil {dc.inuse = true}req <-connrequest{conn:dc,err:err,}return tru e} else if Err = = Nil &&!db.closed && db.maxidleconnslocked () > Len (db.freeconn) {db.freeconn = append (Db.freeconn, DC) db.startcleanerlocked () return True}return false} "if Db.connrequests has a request, Request within range. Because Db.connrequests is a map, and the value is channel. (ChanneL must be quoted!?) Therefore, when the connection condition is satisfied, the request is db.connrequests removed and the incoming new connection DC is placed in the request Req. then return to true.#### after the connection request (return True) "Func" (db *db) adddeplocked (x finalcloser, DEP interface{}) {if db.dep = nil {db.dep = make (Map[finalcloser]depset)}XDEP: = Db.dep[x]if XDEP = = Nil {XDEP = make (Depset) db.dep[x] = Xdep}xdep[dep] = true} "This does not know why to do so, it seems to add a lock (add a judgment), the new connection to the DC lock. # #最后回到sql. Open finally returns the DB. The middle is mainly two steps, the first step is to create a DB instance to return, and the second step is to open a goroutine that has been blocking in the DB, processing the request in the DB into the connection request channel. Once the connection request is placed, a new connection is created. #最后回到gorm. After Open returns a sql.db, "db = &db{db:dbsql,logger:defaultlogger,values:map[string]interface{}{},callbacks: Defaultcallback,dialect:newdialect (dialect, dbsql),}db.parent = dbif Err! = Nil {return}//Send a ping to make sure the D Atabase connection is Alive.if d, OK: = Dbsql. (*sql. DB); OK {if Err = d.ping (); Err! = nil {d.close ()}}return "puts the db into the DB attribute in the DB instance in Gorm, and sets the gorm.db's parent as itself." Finally Ping again, Detects if it can ping the pass. This gorm is then returned to the DB. To this end.--author Clubhouse, reprint please inform the author--319 Click
The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion;
products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the
content of the page makes you feel confusing, please write us an email, we will handle the problem
within 5 days after receiving your email.
If you find any instances of plagiarism from the community, please send an email to:
info-contact@alibabacloud.com
and provide relevant evidence. A staff member will contact you within 5 working days.