一個封裝的Goland數據庫操作方法集——將sql rows轉化成map[string]string

使用原生的Golang進行數據庫CRUD感覺到諸多不變,於是參照之前使用數據庫類的習慣用法,封裝了一個數據庫操作方法集:

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"strings"
	"time"
)

type Dblib struct {
	db *sql.DB
}

const (
	DRIVER_NAME = "mysql"
	USER_NAME   = "root"
	PASS_WORD   = "123456"
	HOST        = "localhost"
	PORT        = "3306"
	DATABASE    = "imooc"
	CHARSET     = "utf8"
)

// 初始化鏈接
func NewMysqlConn() (*Dblib, error) {

	dbDSN := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s", USER_NAME, PASS_WORD, HOST, PORT, DATABASE, CHARSET)

	// 打開連接失敗
	db, err := sql.Open(DRIVER_NAME, dbDSN)
	//defer MysqlDb.Close();
	if err != nil {
		log.Println("dbDSN: " + dbDSN)
		return nil, err
		//panic("數據源配置不正確: " + MysqlDbErr.Error())
	}

	// 最大連接數
	db.SetMaxOpenConns(100)
	// 閒置連接數
	db.SetMaxIdleConns(20)
	// 最大連接週期
	db.SetConnMaxLifetime(100 * time.Second)

	if err = db.Ping(); nil != err {
		panic("數據庫鏈接失敗: " + err.Error())
		return nil, err
	}

	p := new(Dblib)
	p.db = db
	return p, nil
}

type dbRow map[string]interface{}

func scanRow(rows *sql.Rows) (dbRow, error) {
	columns, _ := rows.Columns()

	vals := make([]interface{}, len(columns))
	valsPtr := make([]interface{}, len(columns))

	for i := range vals {
		valsPtr[i] = &vals[i]
	}

	err := rows.Scan(valsPtr...)

	if err != nil {
		return nil, err
	}

	r := make(dbRow)

	for i, v := range columns {
		if va, ok := vals[i].([]byte); ok {
			r[v] = string(va)
		} else {
			r[v] = vals[i]
		}
	}

	return r, nil

}

// 獲取一行記錄
func (d *Dblib) GetOne(sql string, args ...interface{}) (dbRow, error) {
	rows, err := d.db.Query(sql, args...)
	if err != nil {
		return nil, err
	}

	defer rows.Close()
	rows.Next()
	result, err := scanRow(rows)
	return result, err
}

// 獲取多行記錄
func (d *Dblib) GetAll(sql string, args ...interface{}) ([]dbRow, error) {
	rows, err := d.db.Query(sql, args...)
	if err != nil {
		return nil, err
	}

	defer rows.Close()

	result := make([]dbRow, 0)

	for rows.Next() {
		r, err := scanRow(rows)
		if err != nil {
			continue
		}

		result = append(result, r)
	}

	return result, nil

}

// 寫入記錄
func (d *Dblib) Insert(table string, data dbRow) (int64, error) {
	fields := make([]string, 0)
	vals := make([]interface{}, 0)
	placeHolder := make([]string, 0)

	for f, v := range data {
		fields = append(fields, f)
		vals = append(vals, v)
		placeHolder = append(placeHolder, "?")
	}

	sql := fmt.Sprintf("INSERT INTO %s(%s) VALUES(%s) ", table, strings.Join(fields, ","), strings.Join(placeHolder, ","))
	result, err := d.db.Exec(sql, vals...)
	if err != nil {
		return 0, err
	}

	lID, err := result.LastInsertId()
	if err != nil {
		return 0, err
	}

	return lID, nil
}

// 更新記錄
func (d *Dblib) Update(table, condition string, data dbRow, args ...interface{}) (int64, error) {
	params := make([]string, 0)
	vals := make([]interface{}, 0)

	for f, v := range data {
		params = append(params, f+"=?")
		vals = append(vals, v)
	}

	sql := "UPDATE %s SET %s"
	if condition != "" {
		sql += " WHERE %s"
		sql = fmt.Sprintf(sql, table, strings.Join(params, ","), condition)
		vals = append(vals, args...)
	} else {
		sql = fmt.Sprintf(sql, table, strings.Join(params, ","))
	}

	result, err := d.db.Exec(sql, vals...)
	if err != nil {
		return 0, err
	}

	aID, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return aID, nil
}

// 刪除記錄
func (d *Dblib) Delete(table, condition string, args ...interface{}) (int64, error) {
	sql := "DELETE FROM %s "
	if condition != "" {
		sql += "WHERE %s"
		sql = fmt.Sprintf(sql, table, condition)
	} else {
		sql = fmt.Sprintf(sql, table)
	}

	result, err := d.db.Exec(sql, args...)
	if err != nil {
		return 0, err
	}

	aID, err := result.RowsAffected()
	if err != nil {
		return 0, err
	}

	return aID, nil

}

或者:針對數據庫中的數據,使用go語言進行增刪改查

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

//創建mysql 連接
func NewMysqlConn() (db *sql.DB, err error) {
	db, err = sql.Open("mysql", "root:123@tcp(127.0.0.1:3306)/imooc?charset=utf8")
	return
}

//獲取返回值,獲取一條
func GetResultRow(rows *sql.Rows) map[string]string{

	columns, _ := rows.Columns()
	scanArgs := make([]interface{}, len(columns))
	values := make([]interface{}, len(columns))
	for j := range values {
		scanArgs[j] = &values[j]
	}
	record := make(map[string]string)
	for rows.Next() {
		//將行數據保存到record字典
		rows.Scan(scanArgs...)
		for i, v := range values {
			if v != nil {
				//fmt.Println(reflect.TypeOf(col))
				record[columns[i]] = string(v.([]byte))
			}
		}
	}
	return record
}

//獲取所有
func GetResultRows(rows *sql.Rows) map[int]map[string]string {
	fmt.Println("獲取全局數據")
	//返回所有列
	columns, _ := rows.Columns()
	//這裏表示一行所有列的值,用[]byte表示
	vals := make([][]byte, len(columns))
	//這裏表示一行填充數據
	scans := make([]interface{}, len(columns))
	//這裏scans引用vals,把數據填充到[]byte裏
	for k, _ := range vals {
		scans[k] = &vals[k]
	}
	i := 0
	result := make(map[int]map[string]string)
	for rows.Next() {
		//填充數據
		rows.Scan(scans...)
		//每行數據
		row := make(map[string]string)
		//把vals中的數據複製到row中
		for k, v := range vals {
			key := columns[k]
			//這裏把[]byte數據轉成string
			row[key] = string(v)
		}
		//放入結果集
		result[i] = row
		i++
	}
	return result
}

工具類:將map[string]string轉化爲結構體

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"time"
)

//根據結構體中sql標籤映射數據到結構體中並且轉換類型
func DataToStructByTagSql(data map[string]string, obj interface{}) {
	objValue := reflect.ValueOf(obj).Elem()
	for key, value := range data {
		strKey := fmt.Sprintf("data的: %v", key)
		strValue := fmt.Sprintf("data的val:%v", value)
		data[strKey] = strValue
	}

	for i := 0; i < objValue.NumField(); i++ {
		fmt.Println("i的值爲:" + strconv.Itoa(i))
		fmt.Println("obj 結構體對應的下標爲:" + objValue.Type().Field(i).Tag.Get("sql"))

		//獲取sql對應的值
		value := data[objValue.Type().Field(i).Tag.Get("sql")]

		fmt.Println("當前下標回去的Map對應的value值爲:" + value)
		//獲取對應字段的名稱
		name := objValue.Type().Field(i).Name
		//獲取對應字段類型
		structFieldType := objValue.Field(i).Type()
		//獲取變量類型,也可以直接寫"string類型"
		val := reflect.ValueOf(value)
		var err error
		if structFieldType != val.Type() {
			//類型轉換
			val, err = TypeConversion(value, structFieldType.Name()) //類型轉換
			if err != nil {

			}
		}
		//設置類型值
		objValue.FieldByName(name).Set(val)
	}
}

//類型轉換
func TypeConversion(value string, ntype string) (reflect.Value, error) {
	if ntype == "string" {
		return reflect.ValueOf(value), nil
	} else if ntype == "time.Time" {
		t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
		return reflect.ValueOf(t), err
	} else if ntype == "Time" {
		t, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
		return reflect.ValueOf(t), err
	} else if ntype == "int" {
		i, err := strconv.Atoi(value)
		return reflect.ValueOf(i), err
	} else if ntype == "int8" {
		i, err := strconv.ParseInt(value, 10, 64)
		return reflect.ValueOf(int8(i)), err
	} else if ntype == "int32" {
		i, err := strconv.ParseInt(value, 10, 64)
		return reflect.ValueOf(int64(i)), err
	} else if ntype == "int64" {
		i, err := strconv.ParseInt(value, 10, 64)
		return reflect.ValueOf(i), err
	} else if ntype == "float32" {
		i, err := strconv.ParseFloat(value, 64)
		return reflect.ValueOf(float32(i)), err
	} else if ntype == "float64" {
		i, err := strconv.ParseFloat(value, 64)
		return reflect.ValueOf(i), err
	}

	//else if .......增加其他一些類型的轉換
	return reflect.ValueOf(value), errors.New("未知的類型:" + ntype)
}

 

參考:

一個封裝的Goland數據庫操作方法集:https://www.jianshu.com/p/d630e45da6a3

Iris後臺管理Demohttps://www.cnblogs.com/double-W/p/12594817.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章