- 完成 ReqParam/ReqParams 方法实现,用于获取 URL 参数并返回 *Obj - 完成 ReqForm/ReqForms 方法实现,用于获取表单数据并返回 *Obj - 完成 ReqJson/ReqJsons 方法实现,用于获取 JSON Body 并返回 *Obj - 完成 ReqFile/ReqFiles 方法实现,用于获取上传文件 - 完成 ReqData/ReqDatas 方法实现,用于统一封装请求数据获取并返回 *Obj - 更新计划文件状态,标记所有相关功能模块为已完成
189 lines
4.3 KiB
Go
189 lines
4.3 KiB
Go
package db
|
||
|
||
import (
|
||
. "code.hoteas.com/golang/hotime/common"
|
||
"database/sql"
|
||
"encoding/json"
|
||
"errors"
|
||
"reflect"
|
||
"strings"
|
||
)
|
||
|
||
// md5 生成查询的 MD5 哈希(用于缓存)
|
||
func (that *HoTimeDB) md5(query string, args ...interface{}) string {
|
||
strByte, _ := json.Marshal(args)
|
||
str := Md5(query + ":" + string(strByte))
|
||
return str
|
||
}
|
||
|
||
// Query 执行查询 SQL
|
||
func (that *HoTimeDB) Query(query string, args ...interface{}) []Map {
|
||
return that.queryWithRetry(query, false, args...)
|
||
}
|
||
|
||
// queryWithRetry 内部查询方法,支持重试标记
|
||
func (that *HoTimeDB) queryWithRetry(query string, retried bool, args ...interface{}) []Map {
|
||
// 保存调试信息(加锁保护)
|
||
that.mu.Lock()
|
||
that.LastQuery = query
|
||
that.LastData = args
|
||
that.mu.Unlock()
|
||
|
||
defer func() {
|
||
if that.Mode != 0 {
|
||
that.mu.RLock()
|
||
that.Log.Info("SQL:"+that.LastQuery, " DATA:", that.LastData, " ERROR:", that.LastErr.GetError())
|
||
that.mu.RUnlock()
|
||
}
|
||
}()
|
||
|
||
var err error
|
||
var resl *sql.Rows
|
||
|
||
// 主从数据库切换,只有select语句有从数据库
|
||
db := that.DB
|
||
if that.SlaveDB != nil {
|
||
db = that.SlaveDB
|
||
}
|
||
|
||
if db == nil {
|
||
err = errors.New("没有初始化数据库")
|
||
that.LastErr.SetError(err)
|
||
return nil
|
||
}
|
||
|
||
// 处理参数中的 slice 类型
|
||
processedArgs := that.processArgs(args)
|
||
|
||
if that.Tx != nil {
|
||
resl, err = that.Tx.Query(query, processedArgs...)
|
||
} else {
|
||
resl, err = db.Query(query, processedArgs...)
|
||
}
|
||
|
||
that.LastErr.SetError(err)
|
||
if err != nil {
|
||
// 如果还没重试过,尝试 Ping 后重试一次
|
||
if !retried {
|
||
if pingErr := db.Ping(); pingErr == nil {
|
||
return that.queryWithRetry(query, true, args...)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
return that.Row(resl)
|
||
}
|
||
|
||
// Exec 执行非查询 SQL
|
||
func (that *HoTimeDB) Exec(query string, args ...interface{}) (sql.Result, *Error) {
|
||
return that.execWithRetry(query, false, args...)
|
||
}
|
||
|
||
// execWithRetry 内部执行方法,支持重试标记
|
||
func (that *HoTimeDB) execWithRetry(query string, retried bool, args ...interface{}) (sql.Result, *Error) {
|
||
// 保存调试信息(加锁保护)
|
||
that.mu.Lock()
|
||
that.LastQuery = query
|
||
that.LastData = args
|
||
that.mu.Unlock()
|
||
|
||
defer func() {
|
||
if that.Mode != 0 {
|
||
that.mu.RLock()
|
||
that.Log.Info("SQL: "+that.LastQuery, " DATA: ", that.LastData, " ERROR: ", that.LastErr.GetError())
|
||
that.mu.RUnlock()
|
||
}
|
||
}()
|
||
|
||
var e error
|
||
var resl sql.Result
|
||
|
||
if that.DB == nil {
|
||
err := errors.New("没有初始化数据库")
|
||
that.LastErr.SetError(err)
|
||
return nil, that.LastErr
|
||
}
|
||
|
||
// 处理参数中的 slice 类型
|
||
processedArgs := that.processArgs(args)
|
||
|
||
if that.Tx != nil {
|
||
resl, e = that.Tx.Exec(query, processedArgs...)
|
||
} else {
|
||
resl, e = that.DB.Exec(query, processedArgs...)
|
||
}
|
||
|
||
that.LastErr.SetError(e)
|
||
// 判断是否连接断开了,如果还没重试过,尝试重试一次
|
||
if e != nil {
|
||
if !retried {
|
||
if pingErr := that.DB.Ping(); pingErr == nil {
|
||
return that.execWithRetry(query, true, args...)
|
||
}
|
||
}
|
||
return resl, that.LastErr
|
||
}
|
||
|
||
return resl, that.LastErr
|
||
}
|
||
|
||
// processArgs 处理参数中的 slice 类型
|
||
func (that *HoTimeDB) processArgs(args []interface{}) []interface{} {
|
||
processedArgs := make([]interface{}, len(args))
|
||
copy(processedArgs, args)
|
||
for key := range processedArgs {
|
||
arg := processedArgs[key]
|
||
if arg == nil {
|
||
continue
|
||
}
|
||
argType := reflect.ValueOf(arg).Type().String()
|
||
if strings.Contains(argType, "[]") || strings.Contains(argType, "Slice") {
|
||
argLis := ObjToSlice(arg)
|
||
// 将slice转为逗号分割字符串
|
||
argStr := ""
|
||
for i := 0; i < len(argLis); i++ {
|
||
if i == len(argLis)-1 {
|
||
argStr += ObjToStr(argLis[i])
|
||
} else {
|
||
argStr += ObjToStr(argLis[i]) + ","
|
||
}
|
||
}
|
||
processedArgs[key] = argStr
|
||
}
|
||
}
|
||
return processedArgs
|
||
}
|
||
|
||
// Row 数据库数据解析
|
||
func (that *HoTimeDB) Row(resl *sql.Rows) []Map {
|
||
dest := make([]Map, 0)
|
||
strs, _ := resl.Columns()
|
||
|
||
for i := 0; resl.Next(); i++ {
|
||
lis := make(Map, 0)
|
||
a := make([]interface{}, len(strs))
|
||
|
||
b := make([]interface{}, len(a))
|
||
for j := 0; j < len(a); j++ {
|
||
b[j] = &a[j]
|
||
}
|
||
err := resl.Scan(b...)
|
||
if err != nil {
|
||
that.LastErr.SetError(err)
|
||
return nil
|
||
}
|
||
for j := 0; j < len(a); j++ {
|
||
if a[j] != nil && reflect.ValueOf(a[j]).Type().String() == "[]uint8" {
|
||
lis[strs[j]] = string(a[j].([]byte))
|
||
} else {
|
||
lis[strs[j]] = a[j] // 取实际类型
|
||
}
|
||
}
|
||
|
||
dest = append(dest, lis)
|
||
}
|
||
|
||
return dest
|
||
}
|