This is a creation in Article, where the information may have evolved or changed.
Github.com/lib/pq
PG is a pure go write driver of the Postgres database. The author gave us a little joke, the PQ will always be habitually written PG there is no ... The installation method is as follows:
go get github.com/lib/pq
Register
As mentioned earlier, driver needs to call Sql.register to register the Driver.driver type interface driver implementation by name. The init function of the PQ driver in the source Pq/conn.go file, the init function calls Sql.register to register the driver data structure under the name "Postgres".
type drv struct{}func (d *drv)Open(name string)(dirver.Conn, error) { return Open(name)}func init() { sql.Register("postgres", &drv{})}
This postgres will be automatically registered when you import "GITHUB.COM/LIB/PQ" in your code.
The following will explain the code flow in a single query operation.
Sample
First, a sample code ( Note: The code is pseudo-code, only represents the process, not compiled execution ):
package mainimport ( "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 to driver to SQL
As mentioned earlier, the database operation flow is:
Import Package, register driver
In the example above, the SQL package and PQ packages are first import. When the import PQ specifies that the package alias is "_", we just need to register driver with the INIT function of the import PQ package to automatically call the package, without having to use any interface of the package directly.
Sql. Register function in the Sql/sql.go file, the code is as follows, register driver to a global map[string]driver. The 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 first finds driver from drivers by drivername, finds a DB data type after it is found, assigns a value to Db.driver using driver, DataSourceName assigns DB.DSN to initialize the new db.
Then DB. Open calls Db.connectionopener, Db.connectionopener will facilitate all the channel and execute db.opennewconnection.
Db.opennewconnection will call Db.driver.Open (that is, Pq.drv.Open) to validate the DataSourceName, if the parameters in DataSourceName follow the correct format, And there are enough parameters that can be used to connect to the database to return a driver. Conn interface.
The main process of code in PQ is:
drv.Open -> Open -> DialOpen
Db.opennewconnection will wrap a mutex for the driver.conn after it obtains the Driver.open returned to prevent the interaction of concurrent calls to Driver.conn interface.
User Code->sql Package, driver-Sql
The above example code performs two complete operations on the database, one for the query operation, and one for the update operation. This article only explains the query process, which is similar to the update process, which allows readers to follow the code themselves.
The main process for query in SQL is:
sql.DB.Query | -> sql.DB.query | -> sql.DB.queryConn | -> driver.Conn.Prepare (dirver) | -> rowsiFromStatement | -> driver.Stmt.Query (driver)
Query primarily controls the number of connections retry, and then calls query to perform the actual query operation.
Query first gets the Driver.conn interface from the connection pool that is returned by the previous open based on the connection type (default Cachedornewconn). If there is a corresponding connection, call Queryconn to perform the query operation.
Queryconn is performing some verification, lockout operation wait, drop with driver. Conn prepare ready to statement. The process here has been successfully cut seamlessly into the driver section. After the driver layer is prepared by the PREPARE Function statement, control is returned to the SQL package again. After the statement type stmt is obtained, the same layer is encapsulated, and the rowsifromstatement is called.
After some mutex locking operations, rowsifromstatement switches to the driver layer again by calling Stmt.query, and operates on the database by driver the specifically implemented query function, reads rows and returns.
The prepare part of the Conn implementation in PQ is as follows:
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}
The stmt implementation of the PQ in the query part of the source code is as follows:
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}
Reference links
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