func (db *DB) Ping() error {
	return db.PingContext(context.Background())
}
Ping execute a ping context with a background context
package rwdb
import (
	"context"
	"database/sql"
	"database/sql/driver"
	"errors"
	"time"
)
type DB struct {
	cpool           *CPool
	sticky          bool  
	modified        bool
	maxIdle         int
	maxOpen         int
	maxLifetime     time.Duration
	maxIdleModified bool
}
func walk(cpool *CPool, fn func(conn *sql.DB) error) error {
	errors := make(chan error, 1)
	cpool.lock.Lock()
	defer cpool.lock.Unlock()
	for _, conn := range cpool.pool {
		if conn == nil {
			continue
		}
		go func(conn *sql.DB) {
			errors <- fn(conn)
		}(conn)
	}
	if err := <-errors; err != nil {
		return err
	}
	return nil
}
func Open(driver string, dataSourceNames ...string) (*DB, error) {
	var db = &DB{cpool: &CPool{}}
	db.SetSticky(true)
	if len(dataSourceNames) == 0 {
		return nil, errors.New("no data source name available")
	}
	d, err := sql.Open(driver, dataSourceNames[0])
	if err != nil {
		return nil, err
	}
	db.cpool.AddWriter(d)
	for _, conn := range dataSourceNames[1:] {
		go func(conn string) {
			d, _ := sql.Open(driver, conn)
			if db.maxIdleModified {
				d.SetMaxIdleConns(db.maxIdle)
			}
			d.SetConnMaxLifetime(db.maxLifetime)
			d.SetMaxOpenConns(db.maxOpen)
			db.cpool.AddReader(d)
		}(conn)
	}
	return db, nil
}
func (db *DB) next() (*sql.DB, error) {
	if db.sticky && db.modified {
		return db.cpool.Writer()
	}
	return db.cpool.Reader()
}
func (db *DB) SetSticky(stick bool) {
	db.sticky = stick
}
func (db *DB) New() *DB {
	return &DB{
		cpool:  db.cpool,
		sticky: db.sticky,
	}
}
func (db *DB) Driver() driver.Driver {
	writer, _ := db.cpool.Writer()
	return writer.Driver()
}
func (db *DB) Begin() (*sql.Tx, error) {
	writer, err := db.cpool.Writer()
	if err != nil {
		return nil, err
	}
	return writer.Begin()
}
func (db *DB) Exec(query string, args ...interface{}) (sql.Result, error) {
	return db.ExecContext(context.Background(), query, args...)
}
func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
	writer, err := db.cpool.Writer()
	if err != nil {
		return nil, err
	}
	result, err := writer.ExecContext(ctx, query, args...)
	if err == nil {
		if rowAffected, _ := result.RowsAffected(); rowAffected > 0 {
			db.modified = true
		}
	}
	return result, err
}