使用 Go 打造另一款简单实用的 ORM( 二 )

创建一个kdb.go文件,实现RegisterDataBase功能
package kdbimport "database/sql"func RegisterDataBase(kConf KConfig) { for _, dbConf := range kConf.DBConfigList { db, err := sql.Open(dbConf.Driver, dbConf.Dsn) if err != nil { panic(err) } if dbConf.MaxLifetime > 0 { db.SetConnMaxLifetime(dbConf.MaxLifetime) } if dbConf.MaxIdleConns > 0 { db.SetMaxIdleConns(dbConf.MaxIdleConns) } if dbConf.MaxOpenConns > 0 { db.SetMaxOpenConns(dbConf.MaxOpenConns) } if dbConf.Name == "" { dbConf.Name = defaultGroupName } m.addDB(dbConf.Name, dbConf.IsMaster, db) }}第二步: 实现原生SQL查询
在实现原生SQL查询之前,我们先增加一个result.go文件,用来出来查询结果处理,后面将会在这个文件中实现toArrray(), toMap(), toStruct()等功能
type Rows struct {}func (rs *Rows) ToArray() {}func (rs *Rows) ToMap() {}func (rs *Rows) ToStruct(sts interface{}) {}具体的实现我们后面再进行补充 我们再增加一个connection.go用于管理DB的connection
package kdbimport ( "context" "database/sql" "errors" "log")type Connection struct { ctx context.Context conn *sql.Conn tx *sql.Tx name string}func newConnection() *Connection { c := new(Connection) c.ctx = context.Background() return c}func (c *Connection) WithDB(name string) *Connection { c.name = name return c}func (c *Connection) WithContext(ctx context.Context) *Connection { c.ctx = ctx return c}func (c *Connection) Select(query string, bindings []interface{}) *Rows { rows, err := c.queryRows(query, bindings) if err != nil { return &Rows{rs: nil, lastError: err} } return &Rows{rs: rows, lastError: err}}func (c *Connection) Insert(query string, bindings []interface{}) (int64, error) { rs, err := c.exec(query, bindings) if err != nil { return 0, err } return rs.LastInsertId()}func (c *Connection) MultiInsert(query string, bindingsArr [][]interface{}) ([]int64, error) { var stmt *sql.Stmt var err error if c.tx != nil { stmt, err = c.tx.PrepareContext(c.ctx, query) } else { var conn *sql.Conn conn, err = c.getConn() if err != nil { return nil, err } stmt, err = conn.PrepareContext(c.ctx, query) } if err != nil { return nil, err } defer stmt.Close() lastInsertIds := make([]int64, 0) for _, bindings := range bindingsArr { rs, err := stmt.ExecContext(c.ctx, bindings...) if err != nil { return nil, err } lastInsertId, err := rs.LastInsertId() if err != nil { return nil, err } lastInsertIds = append(lastInsertIds, lastInsertId) } return lastInsertIds, nil}func (c *Connection) Update(query string, bindings []interface{}) (int64, error) { rs, err := c.exec(query, bindings) if err != nil { return 0, err } return rs.RowsAffected()}func (c *Connection) Delete(query string, bindings []interface{}) (int64, error) { rs, err := c.exec(query, bindings) if err != nil { return 0, err } return rs.RowsAffected()}func (c *Connection) BeginTransaction() error { if c.tx == nil { conn, err := c.getConn() if err != nil { return err } tx, err := conn.BeginTx(c.ctx, &sql.TxOptions{Isolation: sql.LevelSerializable}) if err != nil { return err } c.tx = tx } return nil}func (c *Connection) Commit() error { if c.tx == nil { return errors.New("no beginTx") } return c.tx.Commit()}func (c *Connection) RollBack() error { if c.tx == nil { return errors.New("no beginTx") } return c.tx.Rollback()}func (c *Connection) queryRows(query string, bindings []interface{}) (rows *sql.Rows, err error) { log.Println("query:", query, "| bindings:", bindings) if c.tx != nil { rows, err = c.tx.QueryContext(c.ctx, query, bindings...) return } var conn *sql.Conn conn, err = c.getConn() if err != nil { return nil, err } rows, err = conn.QueryContext(c.ctx, query, bindings...) return}func (c *Connection) exec(query string, bindings []interface{}) (rs sql.Result, err error) { log.Println("exec:", query, "| bindings:", bindings) if c.tx != nil { rs, err = c.tx.ExecContext(c.ctx, query, bindings...) return } var conn *sql.Conn conn, err = c.getConn() if err != nil { return nil, err } rs, err = conn.ExecContext(c.ctx, query, bindings...) return}func (c *Connection) getConn() (*sql.Conn, error) { var err error var db *sql.DB if c.conn != nil { return c.conn, nil } if c.name != "" { db, err = m.getDB(c.name) } else { db, err = m.getDB() } if err != nil { return nil, err } conn, err := db.Conn(c.ctx) if err != nil { return nil, err } c.conn = conn return c.conn, nil}根据我们期望实现的原生SQL查询的目标,我们需要在kdb.go里增加Select, Insert, Update, Delete, BeginTransaction等方法
package kdbimport ( "context" "database/sql")func RegisterDataBase(kConf KConfig) { for _, dbConf := range kConf.DBConfigList { db, err := sql.Open(dbConf.Driver, dbConf.Dsn) if err != nil { panic(err) } if dbConf.MaxLifetime > 0 { db.SetConnMaxLifetime(dbConf.MaxLifetime) } if dbConf.MaxIdleConns > 0 { db.SetMaxIdleConns(dbConf.MaxIdleConns) } if dbConf.MaxOpenConns > 0 { db.SetMaxOpenConns(dbConf.MaxOpenConns) } if dbConf.Name == "" { dbConf.Name = defaultGroupName } m.addDB(dbConf.Name, dbConf.IsMaster, db) }}func Select(query string, bindings ...interface{}) *Rows { return newConnection().Select(query, bindings)}func Insert(query string, bindings ...interface{}) (LastInsertId int64, err error) { return newConnection().Insert(query, bindings)}func MultiInsert(query string, bindingsArr [][]interface{}) (LastInsertId []int64, err error) { return newConnection().MultiInsert(query, bindingsArr)}func Update(query string, bindings ...interface{}) (RowsAffected int64, err error) { return newConnection().Update(query, bindings)}func Delete(query string, bindings ...interface{}) (RowsAffected int64, err error) { return newConnection().Delete(query, bindings)}func WithDB(name string) *Connection { return newConnection().WithDB(name)}func WithContext(ctx context.Context) *Connection { return newConnection().WithContext(ctx)}func BeginTransaction() (conn *Connection, err error) { conn = newConnection() err = conn.BeginTransaction() if err != nil { return nil, err } return conn, nil}


推荐阅读