Go操作Mysql的正確姿勢

實現mysql外層包裝,簡化使用

package mysqldb

// 引入go插件
import (
    "base_api_go/tbkt/config"
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "log"
    "reflect"
    "strconv"
    "strings"
    "time"
)

// 設置DB全部變量
var db *sql.DB
var ConnPool map[string]*sql.DB
// 初始化數據庫鏈接
func DB(name string) *DBPool{
    DBProxy := new(DBPool)
    Conn := ConnPool[name]
    DBProxy.MysqlConn = Conn
    return DBProxy
}

func init(){
    dbMap := make(map[string]*sql.DB)
    for name, addr := range config.DBConfig{
        var err error
        db, err = sql.Open("mysql", addr)
        // 設置連接池最大鏈接數--不能大於數據庫設置的最大鏈接數
        db.SetMaxOpenConns(100)
        // 設置最大空閒鏈接數--小於設置的鏈接數
        db.SetMaxIdleConns(5)
        // 設置數據庫鏈接超時時間--不能大於數據庫設置的超時時間
        db.SetConnMaxLifetime(time.Second * 5)
        if err != nil {
            log.Println("鏈接異常")
        }
        dbMap[name] = db
    }
    ConnPool = dbMap
}

// 數據庫操作處理結構體
type DBPool struct {
    MysqlConn *sql.DB   `數據庫鏈接池`
    DBName string `數據庫名字`
    TableName   string  `數據表名字`
    SelectCondition []interface{}   `選擇條件`
    WhereCondition  []map[string]interface{}    `查詢條件`
    GroupCondition  []interface{}   `分組條件`
    OrderCondition  []interface{}   `排序條件`
}

// 查詢數據表獲取
func(p *DBPool)Table(name string) *DBPool{
    p.TableName = name
    return p
}

// 查詢select條件入參,入參類似python的args
func(p *DBPool)Select(params ...interface{}) *DBPool{
    p.SelectCondition = params
    return p
}

// 查詢where條件入參,入參類似於python的args
func(p *DBPool)Filter(query interface{}, values ...interface{}) *DBPool{
    p.WhereCondition = append(p.WhereCondition, map[string]interface{}{"query": query, "args": values})
    return p
}

// 定義數據庫分組函數,入參類似於python的args
func(p *DBPool)GroupBy(params ...interface{}) *DBPool{
    p.GroupCondition = params
    return p
}

// 定義數據庫排序函數,入參類似於python的args
func(p *DBPool)OrderBy(params ...interface{}) *DBPool{
    p.OrderCondition = params
    return p
}

// SQL拼接處理
func (p *DBPool)Sql() string{
    // 匿名函數interface轉slice--需要時調用
    fn := func (arr interface{}) []interface{} {
        v := reflect.ValueOf(arr)
        if v.Kind() != reflect.Slice {
            panic("The Filter Params Valid")
        }
        vLen := v.Len()
        ret := make([]interface{}, vLen)
        for i := 0; i < vLen; i++ {
            ret[i] = v.Index(i).Interface()
        }
        return ret
    }
    // 處理select條件
    SelectFilter := ""
    for _, vs := range p.SelectCondition{
        if SelectFilter == "" {
            SelectFilter += fmt.Sprintf("%s", vs)
        }else {
            SelectFilter += fmt.Sprintf(",%s", vs)
        }
    }
    // 沒有設置獲取數據字段,默認查詢全部
    if SelectFilter == "" {
        SelectFilter = "*"
    }
    // 處理where條件
    WhereFilter := ""
    if len(p.WhereCondition[0]) > 0{
        FilterList := strings.Split(p.WhereCondition[0]["query"].(string), "AND")
        // 匿名函數處理where入參, interface轉slice
        WhereList := fn(p.WhereCondition[0]["args"])
        // 組合where條件
        for index, value := range FilterList{
            // 參數分割,並去除空格
            NewValue := strings.TrimSpace(strings.Split(value, "?")[0])
            WhereValue := WhereList[index]
            // 入參類型斷言
            switch reflect.ValueOf(WhereValue).Kind(){
                case reflect.Int:
                    if WhereFilter == "" {
                        WhereFilter += fmt.Sprintf("WHERE %v%d", NewValue, WhereList[index])
                    }else{
                        WhereFilter += fmt.Sprintf(" AND %v%d", NewValue, WhereList[index])
                    }
                case reflect.String:
                    if WhereFilter == "" {
                        WhereFilter += fmt.Sprintf("WHERE %v'%v'", NewValue, WhereList[index])
                    }else{
                        WhereFilter += fmt.Sprintf(" AND %v'%v'", NewValue, WhereList[index])
                    }
                case reflect.Slice:
                    // 匿名函數處理where入參, interface轉slice
                    NewList := fn(WhereValue)
                    FilterWhere := ""
                    for v := range NewList{
                        switch reflect.ValueOf(v).Kind() {
                            case reflect.Int:
                                if FilterWhere == "" {
                                    FilterWhere += fmt.Sprintf("%d", v)
                                } else {
                                    FilterWhere += fmt.Sprintf(",%d", v)
                                }
                            case reflect.String:
                                if FilterWhere == "" {
                                    FilterWhere += fmt.Sprintf("'%v'", v)
                                } else {
                                    FilterWhere += fmt.Sprintf(",'%v'", v)
                                }
                            default:
                                panic("1001:The Params Valid")
                            }
                    }
                    if WhereFilter == "" {
                        WhereFilter += fmt.Sprintf("WHERE %v (%v)", NewValue, FilterWhere)
                    }else{
                        WhereFilter += fmt.Sprintf(" AND %v (%v)", NewValue, FilterWhere)
                    }
                default:
                    panic("1002:The Params Valid")
            }
        }
    }
    // 處理分組條件
    GroupFilter := ""
    for _, vg := range p.GroupCondition{
        if GroupFilter == "" {
            GroupFilter += fmt.Sprintf("GROUP BY %s", vg)
        }else {
            GroupFilter += fmt.Sprintf(",%s", vg)
        }
    }
    // 處理排序條件
    OrderFilter := ""
    for _, vo := range p.OrderCondition{
        if OrderFilter == "" {
            OrderFilter += fmt.Sprintf("ORDER BY %s", vo)
        }else {
            OrderFilter += fmt.Sprintf(",%s", vo)
        }
    }
    // 格式化生成SQL
    Sql := fmt.Sprintf("SELECT %v FROM %v %v ", SelectFilter, p.TableName, WhereFilter)
    return Sql
}

// 數據庫返回數據處理,返回數據類型爲slice,slice內層爲map
func dealMysqlRows(rows *sql.Rows) []map[string]interface{}{
    defer rows.Close()
    // 獲取列名
    columns, err := rows.Columns()
    columnTypes, _ := rows.ColumnTypes()
    // 獲取每列的數據類型
    ColumnTypeMap := make(map[string]string)
    for _, v := range columnTypes{
        ColumnTypeMap[v.Name()] = v.DatabaseTypeName()
    }
    CheckError(err, 0)
    // 定義返回參數的slice
    retValues := make([]sql.RawBytes, len(columns))
    // 定義數據列名的slice
    scanArgs := make([]interface{}, len(retValues))
    // 數據列賦值
    for i := range retValues{
        scanArgs[i] = &retValues[i]
    }
    // 定義返回數據類型slice
    var resList []map[string]interface{}
    // 返回數據賦值
    for rows.Next()  {
        // 檢測數據列是否超出
        err = rows.Scan(scanArgs...)
        CheckError(err, 0)
        // 內層數據格式
        rowMap := make(map[string]interface{})
        for i, colVal := range retValues{
            if colVal != nil{
                keyName := columns[i]
                value := string(colVal)
                // 數據類型轉換
                switch ColumnTypeMap[keyName] {
                    case "INT":
                        newValue, _ := strconv.Atoi(value)
                        rowMap[keyName] = newValue
                    case "TINYINT":
                        newValue, _ := strconv.Atoi(value)
                        rowMap[keyName] = newValue
                    case "VARCHAR":
                        rowMap[keyName] = value
                    case "DATETIME":
                        newValue, _ := time.Parse(value, value)
                        rowMap[keyName] = newValue
                    default:
                        rowMap[keyName] = value
                }
            }
        }
        resList = append(resList, rowMap)
    }
    return resList
}

// 獲取第一條數據,返回數據類型爲map
func(p *DBPool) Get() map[string]interface{}{
    RetOne := make(map[string]interface{})
    // 數據庫操作結束,釋放鏈接
    GetSql := p.Sql() + "LIMIT 1"
    rows, err := p.MysqlConn.Query(GetSql)
    CheckError(err, 0)
    // 數據獲取
    RetMap := dealMysqlRows(rows)
    if len(RetMap) > 0{
        RetOne = RetMap[0]
    }
    return RetOne
}

// 獲取多條數據,返回數據類型爲slice,slice內層爲map
func(p *DBPool) All() []map[string]interface{}{
    // 數據庫操作結束,釋放鏈接
    GetSql := p.Sql()
    rows, err := p.MysqlConn.Query(GetSql)
    CheckError(err, 0)
    // 數據獲取
    RetMap := dealMysqlRows(rows)
    return RetMap
}

// 定義創建數據方法,返回最後的ID
func(p *DBPool) Create(params map[string]interface{}) int{
    // 數據庫操作結束,釋放鏈接
    // 自定待創建的函數和參數
    InsertCols, InsertArgs := "", ""
    for k, v := range params{
        // 數據列只能爲string類型
        if InsertCols == "" {
            InsertCols += fmt.Sprintf("%s", k)
        }else {
            InsertCols += fmt.Sprintf(",%s", k)
        }
        // 判斷數據類型,類型斷言判斷
        switch v.(type) {
            case int:
                if InsertArgs == "" {
                    InsertArgs += fmt.Sprintf("%d", v)
                }else {
                    InsertArgs += fmt.Sprintf(",%d", v)
                }
            case string:
                if InsertArgs == "" {
                    InsertArgs += fmt.Sprintf("'%s'", v)
                }else{
                    InsertArgs += fmt.Sprintf(",'%s'", v)
                }
            case float64:
                if InsertArgs == "" {
                    InsertArgs += fmt.Sprintf("%f", v)
                }else {
                    InsertArgs += fmt.Sprintf(",%f", v)
                }
        }
    }
    // 開啓MySql事務
    tx, err := p.MysqlConn.Begin()
    CheckError(err, 1)
    // 組合數據寫入SQL
    InsertSql := fmt.Sprintf("INSERT INTO %v(%v) VALUES (%v);", p.TableName, InsertCols, InsertArgs)
    retData, err := p.MysqlConn.Exec(InsertSql)
    CheckError(err, 0)
    LastId, err := retData.LastInsertId()
    if err != nil{
        log.Println("數據創建失敗,事務回滾")
        tx.Rollback()
    }
    tx.Commit()
    return int(LastId)
}


// 定義更新數據方法,返回影響的行數
func(p *DBPool) Update(params map[string]interface{}) int{
    // 數據庫操作結束,釋放鏈接
    // 處理where條件
    WhereFilter := ""
    for _, vw := range p.WhereCondition{
        if WhereFilter == "" {
            WhereFilter += fmt.Sprintf("%s", vw)
        }else {
            WhereFilter += fmt.Sprintf(" AND %s", vw)
        }
    }
    // 定義待創建的函數和參數
    UpdateArgs := ""
    for k, v := range params{
        // 數據列只能爲string類型
        if UpdateArgs == "" {
            // 判斷數據類型,類型斷言判斷
            switch v.(type) {
                case int:
                    UpdateArgs += fmt.Sprintf("%s=%d", k, v)
                case string:
                    UpdateArgs += fmt.Sprintf("%s='%s'", k, v)
                case float64:
                    UpdateArgs += fmt.Sprintf("%s=%f", k, v)
                }
        }else {
            // 判斷數據類型,類型斷言判斷
            switch v.(type) {
                case int:
                    UpdateArgs += fmt.Sprintf(",%s=%d", k, v)
                case string:
                    UpdateArgs += fmt.Sprintf(",%s='%s'", k, v)
                case float64:
                    UpdateArgs += fmt.Sprintf(",%s=%f", k, v)
                }
        }
    }
    // 組合數據更新SQL
    UpdateSql := fmt.Sprintf("UPDATE %v SET %v WHERE %v;", p.TableName, UpdateArgs, WhereFilter)
    // 開啓MySql事務
    tx, err := p.MysqlConn.Begin()
    CheckError(err, 1)
    retData, err := p.MysqlConn.Exec(UpdateSql)
    CheckError(err, 1)
    ARows, err := retData.RowsAffected()
    if err != nil{
        log.Println("數據更新失敗,事務回滾")
        tx.Rollback()
    }
    // 提交事務
    tx.Commit()
    return int(ARows)
}

// 定義刪除數據方法
func(p *DBPool) Delete() int{
    // 數據庫操作結束,釋放鏈接
    // 處理where條件
    WhereFilter := ""
    for _, vw := range p.WhereCondition{
        if WhereFilter == "" {
            WhereFilter += fmt.Sprintf("%s", vw)
        }else {
            WhereFilter += fmt.Sprintf(" AND %s", vw)
        }
    }
    // 組合刪除數據SQL
    DeleteSql := fmt.Sprintf("DELETE FROM %v WHERE %v", p.TableName, WhereFilter)
    // 開啓MySql事務
    tx, err := p.MysqlConn.Begin()
    retData, err := p.MysqlConn.Exec(DeleteSql)
    CheckError(err, 0)
    ARows, err := retData.RowsAffected()
    if err != nil{
        log.Println("數據刪除失敗,事務回滾")
        tx.Rollback()
    }
    // 提交事務
    tx.Commit()
    return int(ARows)
}


// 查詢執行SQL方法
func(p *DBPool) Execute(Sql string) int{
    // 數據庫操作結束,釋放鏈接
    retData, err := p.MysqlConn.Exec(Sql)
    // 開啓MySql事務
    tx, err := p.MysqlConn.Begin()
    CheckError(err, 0)
    ARows, err := retData.RowsAffected()
    if err != nil{
        log.Println("數據庫執行失敗,事務回滾")
        tx.Rollback()
    }
    // 提交事務
    tx.Commit()
    return int(ARows)
}

// 定義執行SQL返回一條數據方法
func(p *DBPool) FetchOne(Sql string) map[string]interface{}{
    // 數據庫操作結束,釋放鏈接
    rows, err := p.MysqlConn.Query(Sql)
    CheckError(err, 0)
    // 數據獲取
    RetMap := dealMysqlRows(rows)
    return RetMap[0]
}

// 定義執行SQL返回多條數據方法
func(p *DBPool) FetchAll(Sql string) []map[string]interface{}{
    // 數據庫操作結束,釋放鏈接
    rows, err := p.MysqlConn.Query(Sql)
    CheckError(err, 0)
    // 數據獲取
    RetMap := dealMysqlRows(rows)
    return RetMap
}

使用

import . "mysqldb"
AccountData := DB("base").Table("auth_account").Filter("id=?", AccountId).Get()
// AccountData map類型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章