|
@@ -0,0 +1,346 @@
|
|
|
+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)
|
|
|
+}
|