package db import ( "database/sql" "errors" "fmt" "sync" "time" "git.chuangxin1.com/cx/tyr" // mysql _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) // DB error code const ( DBErrCodeOK = 0 // DBErrCodeOK ok DBErrCodeException = 1 // DBErrCodeException exception DBErrCodeExists = 2 // DBErrCodeExists exists DBErrCodeNotFound = 3 // DBErrCodeNotFound not found DBErrCodeAuthorized = 4 // DBErrCodeAuthorized authorized DBErrCodeNotConnect = 5 // DBErrCodeNotConnect connect error ) // Config config type Config struct { Driver string DNS string MaxOpenConns int MaxIdle int MaxLifetime time.Duration } // Reply db exec return insert/update/delete type Reply struct { OK bool Err error LastErr error ErrCode int LastID int64 RowsAffected int64 } // ReplyToReplyData db reply to response func ReplyToReplyData(reply Reply) *tyr.ReplyData { status := tyr.ErrOk if !reply.OK { switch reply.ErrCode { case DBErrCodeException: status = tyr.ErrException case DBErrCodeExists: status = tyr.ErrDataExists case DBErrCodeNotFound: status = tyr.ErrDataNotFound case DBErrCodeAuthorized: status = tyr.ErrUnAuthorized case DBErrCodeNotConnect: status = tyr.ErrNotFound } return tyr.ErrReplyData(status, reply.LastErr.Error()) } return tyr.OkReplyData() } var ( config Config db *sqlx.DB err error once sync.Once ) // DB define type DB struct { conn *sqlx.DB tx *sqlx.Tx } // SetDbConfig set func SetDbConfig(cfg Config) { config.Driver = cfg.Driver config.DNS = cfg.DNS config.MaxOpenConns = cfg.MaxOpenConns config.MaxIdle = cfg.MaxIdle config.MaxLifetime = cfg.MaxLifetime * time.Second } // ErrSQLNoRows check norows error func ErrSQLNoRows(err error) bool { if err == sql.ErrNoRows { return true } return false } // ReplyOk exec ok func ReplyOk(rowsAffected, lastID int64) Reply { var reply Reply reply.OK = true reply.ErrCode = 0 reply.LastID = lastID reply.RowsAffected = rowsAffected return reply } // ReplyFaild exec faild func ReplyFaild(errCode int, err, errText error) (reply Reply) { reply.OK = false reply.ErrCode = errCode reply.LastID = -1 reply.RowsAffected = -1 reply.Err = err reply.LastErr = errText return } // NewDB new DB object func NewDB() *DB { return &DB{} } // ReleaseDB free db connect func ReleaseDB() { if db != nil { db.Close() } } // NewConfigDB new DB dynamic object func NewConfigDB(config Config) (dbx *DB, err error) { dbx = &DB{} dbx.conn, err = sqlx.Connect(config.Driver, config.DNS) if err == nil { dbx.conn.SetMaxOpenConns(config.MaxOpenConns) dbx.conn.SetMaxIdleConns(config.MaxIdle) dbx.conn.SetConnMaxLifetime(config.MaxLifetime) dbx.conn.Ping() } return } // ReleaseConfigDB free db connect func ReleaseConfigDB(dbx *DB) { if dbx.conn != nil { dbx.conn.Close() } } func connect() (dbx *sqlx.DB, err error) { once.Do(func() { db, err = sqlx.Connect(config.Driver, config.DNS) if err == nil { db.DB.SetMaxOpenConns(config.MaxOpenConns) db.DB.SetMaxIdleConns(config.MaxIdle) db.DB.SetConnMaxLifetime(config.MaxLifetime) db.Ping() } }) dbx = db return } // Connect connect to database func (d *DB) Connect() (err error) { if d.conn != nil { return } d.conn, err = connect() return } // Close close database connect func (d *DB) Close() { //d.conn.Close() } // BeginTrans begin trans func (d *DB) BeginTrans() (err error) { d.conn, err = connect() if err != nil { return } d.tx = d.conn.MustBegin() return } // Commit commit func (d *DB) Commit() error { return d.tx.Commit() } // Rollback rollback func (d *DB) Rollback() error { return d.tx.Rollback() } // TransExec trans execute func (d *DB) TransExec(query string, args interface{}) (LastInsertId, RowsAffected int64, err error) { if rs, err := d.tx.NamedExec(query, args); err == nil { RowsAffected, _ = rs.RowsAffected() LastInsertId, _ = rs.LastInsertId() } return } // TransUpdate trans update func (d *DB) TransUpdate(query string, args interface{}) (reply Reply) { var ( err error rs sql.Result ) if rs, err = d.tx.NamedExec(query, args); err == nil { a, _ := rs.RowsAffected() reply = ReplyOk(a, 0) } else { reply = ReplyFaild(DBErrCodeException, err, errors.New(`数据执行错误`)) } return } // Rows get rows func (d *DB) Rows(dest interface{}, query string, args interface{}) error { err := d.Connect() if err != nil { return err } defer d.Close() nstmt, err := d.conn.PrepareNamed(query) if err != nil { return err } defer nstmt.Close() err = nstmt.Select(dest, args) return err } // Row get row func (d *DB) Row(dest interface{}, query string, args interface{}) error { err := d.Connect() if err != nil { return err } defer d.Close() nstmt, err := d.conn.PrepareNamed(query) if err != nil { return err } defer nstmt.Close() err = nstmt.Get(dest, args) return err } // InsertReply insert and return DbReply func (d *DB) InsertReply(query string, args interface{}) (reply Reply) { var ( err error rs sql.Result ) err = d.Connect() if err != nil { reply = ReplyFaild(DBErrCodeNotConnect, err, errors.New(`数据库连接错误`)) return } defer d.Close() if rs, err = d.conn.NamedExec(query, args); err == nil { a, _ := rs.RowsAffected() n, _ := rs.LastInsertId() reply = ReplyOk(a, n) } else { reply = ReplyFaild(DBErrCodeException, err, errors.New(`数据执行错误`)) } return } // UpdateReply update/delete and return DbReply func (d *DB) UpdateReply(query string, args interface{}) (reply Reply) { var ( err error rs sql.Result ) err = d.Connect() if err != nil { reply = ReplyFaild(DBErrCodeNotConnect, err, errors.New(`数据库连接错误`)) return } defer d.Close() if rs, err = d.conn.NamedExec(query, args); err == nil { a, _ := rs.RowsAffected() reply = ReplyOk(a, 0) } else { reply = ReplyFaild(DBErrCodeException, err, errors.New(`数据执行错误`)) } return } // Insert insert into func (d *DB) Insert(query string, args interface{}) (LastInsertId, RowsAffected int64, err error) { err = d.Connect() if err != nil { return } defer d.Close() if rs, err := d.conn.NamedExec(query, args); err == nil { LastInsertId, _ = rs.LastInsertId() RowsAffected, _ = rs.RowsAffected() } return } // Update update/delete func (d *DB) Update(query string, args interface{}) (RowsAffected int64, err error) { err = d.Connect() if err != nil { return } defer d.Close() if rs, err := d.conn.NamedExec(query, args); err == nil { RowsAffected, _ = rs.RowsAffected() } return } // Limit MySQL limit func (d *DB) Limit(page, pagesize int) string { return fmt.Sprintf(" limit %d, %d", (page-1)*pagesize, pagesize) }