712 lines
17 KiB
Go
712 lines
17 KiB
Go
/*
|
||
=================================================================================
|
||
* License: GPL-2.0 license
|
||
* Author: 众产® https://ciy.cn/code
|
||
* Version: 0.1.0
|
||
=================================================================================
|
||
单数据库连接池 NewCiyMysql
|
||
=================================================================================
|
||
db, err = c.NewCiyMysql("user:pass@tcp(localhost:3306)/dbname", 最大连接数, 空闲连接数, 保活秒) //main初始化
|
||
defer db.Close()
|
||
db.Err() //查看最后一条错误信息。 db.ClearError() 清空历史错误。 db.Error //查看原始错误数组。
|
||
db.Get(csql, &total) //获取多行数据
|
||
db.Getone(csql) //获取单行数据,返回[]map[string]any
|
||
db.Get1(csql) //获取单行数据,返回any
|
||
db.GetField(csql) //获取列备注及排序
|
||
db.Getdbcodes(csql) //获取列备注字典
|
||
|
||
db.Execute(csql, any...) //执行带问号的SQL语句,返回影响行数和最后插入ID
|
||
db.Update(csql, map) //更新数据,返回影响行数
|
||
db.Insert(csql, map) //新增数据,返回最后插入ID
|
||
db.Delete(csql, backup) //删除数据,返回影响行数。支持副表备份、删除标记、直接删除。
|
||
db.Tran(fn) //批处理事务。自动Begin/Commit/Rollback
|
||
|
||
=================================================================================
|
||
查询示例:
|
||
csql := c.NewCiySQL("user")
|
||
csql.Where("name like", "王").Where("age>", 18).Order("id desc").Limit(1, 10)
|
||
var total int //全部行数
|
||
list, err := c.DB.Get(csql, &total)
|
||
|
||
for _, v := range list {
|
||
id := c.Getint(v, "id")
|
||
}
|
||
|
||
增删改示例:
|
||
=================================================================================
|
||
*/
|
||
package zciyon
|
||
|
||
import (
|
||
"database/sql"
|
||
"fmt"
|
||
"runtime"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
type CiyMysql struct {
|
||
Db *sql.DB
|
||
Tx *sql.Tx
|
||
Error []string
|
||
UserID int
|
||
Health int //健康状态,0-100,越小越好
|
||
}
|
||
|
||
// 单个数据库连接池,平时单独使用
|
||
func NewCiyMysql(dsn string, maxopenconn int, maxidelconn int, maxlifesec int) (*CiyMysql, error) {
|
||
db := &CiyMysql{}
|
||
db.Error = make([]string, 0)
|
||
db.Health = 50
|
||
db.UserID = 0
|
||
var err error
|
||
db.Db, err = sql.Open("mysql", dsn)
|
||
if err != nil {
|
||
db.addError("NewCiyMysql.Open", err)
|
||
return nil, err
|
||
}
|
||
err = db.Db.Ping()
|
||
if err != nil {
|
||
db.addError("NewCiyMysql.Ping", err)
|
||
return nil, err
|
||
}
|
||
if maxopenconn <= 0 {
|
||
maxopenconn = runtime.NumCPU()*2 + 1
|
||
}
|
||
if maxidelconn < 1 {
|
||
maxidelconn = 2
|
||
}
|
||
if maxlifesec < 1 {
|
||
maxlifesec = 3600 * 6
|
||
}
|
||
db.Db.SetMaxOpenConns(maxopenconn) //最大连接数
|
||
db.Db.SetMaxIdleConns(maxidelconn) //保持空闲的连接数
|
||
db.Db.SetConnMaxLifetime(time.Duration(maxlifesec) * time.Second)
|
||
return db, nil
|
||
}
|
||
|
||
func (thos *CiyMysql) MonitorHealth(sec float64) {
|
||
go func() {
|
||
for {
|
||
Sleep(sec)
|
||
thos.Health = 50
|
||
stat := thos.Db.Stats()
|
||
//Health%=已连接数+等待连接数*2/最大连接数
|
||
thos.Health = (stat.OpenConnections + int(stat.WaitCount)*2) * 100 / stat.MaxOpenConnections
|
||
Clog("health:%d", thos.Health)
|
||
}
|
||
}()
|
||
}
|
||
func (thos *CiyMysql) Close() error {
|
||
return thos.Db.Close()
|
||
}
|
||
func (thos *CiyMysql) addError(from string, err error) {
|
||
thos.Error = append(thos.Error, from+":"+err.Error())
|
||
}
|
||
func (thos *CiyMysql) Err() string {
|
||
if len(thos.Error) == 0 {
|
||
return ""
|
||
}
|
||
return thos.Error[len(thos.Error)-1]
|
||
}
|
||
func (thos *CiyMysql) ClearError() {
|
||
thos.Error = make([]string, 0)
|
||
}
|
||
|
||
func (thos *CiyMysql) Execute(sqlstr string, argdata ...any) (int, int, error) {
|
||
var rett sql.Result
|
||
var err error
|
||
if thos.Tx != nil {
|
||
rett, err = thos.Tx.Exec(sqlstr, argdata...)
|
||
} else {
|
||
rett, err = thos.Db.Exec(sqlstr, argdata...)
|
||
}
|
||
if err != nil {
|
||
thos.addError("Execute.Exec", err)
|
||
return 0, 0, err
|
||
}
|
||
affect, err := rett.RowsAffected()
|
||
if err != nil {
|
||
thos.addError("Execute.RowsAffected", err)
|
||
return 0, 0, err
|
||
}
|
||
var lastid int64
|
||
if strings.HasPrefix(sqlstr, "insert") {
|
||
lastid, err = rett.LastInsertId()
|
||
if err != nil {
|
||
thos.addError("Execute.LastInsertId", err)
|
||
return 0, 0, err
|
||
}
|
||
}
|
||
return int(lastid), int(affect), nil
|
||
}
|
||
|
||
func (thos *CiyMysql) Update(csql *CiySQL, updata map[string]any) (int, error) {
|
||
if csql.rawsql != "" {
|
||
e := fmt.Errorf("forbid use rawsql")
|
||
thos.addError("Update.Init", e)
|
||
return 0, e
|
||
}
|
||
if len(updata) == 0 {
|
||
e := fmt.Errorf("updata empty")
|
||
thos.addError("Update.Init", e)
|
||
return 0, e
|
||
}
|
||
if csql.sqlwhere == "" {
|
||
e := fmt.Errorf("no where")
|
||
thos.addError("Update.Init", e)
|
||
return 0, e
|
||
}
|
||
sets := []string{}
|
||
datas := []any{}
|
||
|
||
for field, data := range updata {
|
||
if field == "id" {
|
||
continue
|
||
}
|
||
if arr, ok := data.([]string); ok {
|
||
sets = append(sets, "`"+field+"`="+arr[0])
|
||
} else {
|
||
sets = append(sets, "`"+field+"`=?")
|
||
datas = append(datas, data)
|
||
}
|
||
}
|
||
|
||
setstr := strings.Join(sets, ",")
|
||
combined := make([]any, 0, len(datas)+len(csql.tsmt))
|
||
combined = append(combined, datas...)
|
||
combined = append(combined, csql.tsmt...)
|
||
sqlstr := "update " + csql.table + " set " + setstr + csql.Buildwhere()
|
||
_, lastaffect, err := thos.Execute(sqlstr, combined...)
|
||
if err != nil {
|
||
thos.addError("Update.Execute", err)
|
||
return 0, err
|
||
}
|
||
return lastaffect, nil
|
||
}
|
||
func (thos *CiyMysql) Insert(csql *CiySQL, updata map[string]any) (int, error) {
|
||
if csql.rawsql != "" {
|
||
e := fmt.Errorf("forbid use rawsql")
|
||
thos.addError("Insert.Init", e)
|
||
return 0, e
|
||
}
|
||
if len(updata) == 0 {
|
||
e := fmt.Errorf("updata empty")
|
||
thos.addError("Insert.Init", e)
|
||
return 0, e
|
||
}
|
||
columns := []string{}
|
||
values := []string{}
|
||
datas := []any{}
|
||
|
||
for field, data := range updata {
|
||
columns = append(columns, "`"+field+"`")
|
||
if arr, ok := data.([]string); ok {
|
||
values = append(values, arr[0])
|
||
} else {
|
||
values = append(values, "?")
|
||
datas = append(datas, data)
|
||
}
|
||
}
|
||
columnstr := strings.Join(columns, ",")
|
||
valuestr := strings.Join(values, ",")
|
||
sqlstr := "insert into " + csql.table + " (" + columnstr + ") values (" + valuestr + ")"
|
||
lastid, _, err := thos.Execute(sqlstr, datas...)
|
||
if err != nil {
|
||
thos.addError("Insert.Execute", err)
|
||
return 0, err
|
||
}
|
||
return lastid, nil
|
||
}
|
||
|
||
func (thos *CiyMysql) Delete(csql *CiySQL, argbackup ...int) (int, error) {
|
||
if csql.rawsql != "" {
|
||
e := fmt.Errorf("forbid use rawsql")
|
||
thos.addError("Delete.Init", e)
|
||
return 0, e
|
||
}
|
||
if csql.sqlwhere == "" {
|
||
e := fmt.Errorf("no where")
|
||
thos.addError("Delete.Init", e)
|
||
return 0, e
|
||
}
|
||
var lastaffect int
|
||
var err error
|
||
var backup int = CIYDB_DELETE_BACKUP_NONE
|
||
if len(argbackup) > 0 {
|
||
backup = argbackup[0]
|
||
}
|
||
if backup == CIYDB_DELETE_BACKUP_TABLE { //写到备份表
|
||
var columns []string
|
||
columns, err = thos.getcolumn(csql)
|
||
if err != nil {
|
||
thos.addError("Delete.getcolumn", err)
|
||
return 0, err
|
||
}
|
||
columnstr := strings.Join(columns, ",")
|
||
sqlstr := "insert into " + csql.table + "_bak (" + columnstr + ") select " + columnstr + " from " + csql.table + csql.Buildwhere()
|
||
_, _, err = thos.Execute(sqlstr)
|
||
if err != nil {
|
||
thos.addError("Delete.insertbak", err)
|
||
return 0, err
|
||
}
|
||
}
|
||
if backup == CIYDB_DELETE_BACKUP_FIELD { //修改删除标志位
|
||
sqlstr := "update " + csql.table + " set deltimes=" + Tostr(Tostamp()) + csql.Buildwhere()
|
||
_, lastaffect, err = thos.Execute(sqlstr, csql.tsmt...)
|
||
if err != nil {
|
||
thos.addError("Delete.deltimes", err)
|
||
return 0, err
|
||
}
|
||
} else { //删除数据
|
||
sqlstr := "delete from " + csql.table + csql.Buildwhere()
|
||
_, lastaffect, err = thos.Execute(sqlstr, csql.tsmt...)
|
||
if err != nil {
|
||
thos.addError("Delete.delete", err)
|
||
return 0, err
|
||
}
|
||
}
|
||
return lastaffect, nil
|
||
}
|
||
|
||
func (thos *CiyMysql) Tran(fn func() error) (err error) {
|
||
thos.Tx, err = thos.Db.Begin()
|
||
if err != nil {
|
||
thos.Tx = nil
|
||
return err
|
||
}
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
err = fmt.Errorf("%v", r)
|
||
thos.addError("Tran.catch", fmt.Errorf("%v", r))
|
||
if thos.Tx != nil {
|
||
err2 := thos.Tx.Rollback()
|
||
CiyVars.Func_rollback++
|
||
thos.Tx = nil
|
||
if err2 != nil {
|
||
thos.addError("Tran.catch.Rollback", err2)
|
||
err = fmt.Errorf("%v[%v]", err2, err)
|
||
}
|
||
}
|
||
} else {
|
||
if thos.Tx != nil {
|
||
err2 := thos.Tx.Commit()
|
||
CiyVars.Func_commit++
|
||
thos.Tx = nil
|
||
if err2 != nil {
|
||
thos.addError("Tran.catch.Commit", err2)
|
||
err = err2
|
||
}
|
||
}
|
||
}
|
||
}()
|
||
err = fn()
|
||
if err != nil {
|
||
if thos.Tx != nil {
|
||
errtx := thos.Tx.Rollback()
|
||
CiyVars.Func_rollback++
|
||
if errtx != nil {
|
||
thos.addError("Tran.Rollback", err)
|
||
}
|
||
thos.Tx = nil
|
||
}
|
||
thos.addError("Tran", err)
|
||
} else {
|
||
if thos.Tx != nil {
|
||
errtx := thos.Tx.Commit()
|
||
CiyVars.Func_commit++
|
||
thos.Tx = nil
|
||
if errtx != nil {
|
||
thos.addError("Tran.Commit", errtx)
|
||
}
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
func (thos *CiyMysql) getcolumn(csql *CiySQL) ([]string, error) {
|
||
rows, err := thos.Db.Query("select * from " + csql.table + " where id=0")
|
||
if err != nil {
|
||
return nil, fmt.Errorf("query: %v", err)
|
||
}
|
||
defer rows.Close()
|
||
columns, err := rows.Columns()
|
||
if err != nil {
|
||
return nil, fmt.Errorf("columns: %v", err)
|
||
}
|
||
return columns, nil
|
||
}
|
||
func (thos *CiyMysql) calcolumn(csql *CiySQL) error {
|
||
if csql.sqlcolumn == "" {
|
||
csql.sqlcolumn = "*"
|
||
}
|
||
if !strings.HasPrefix(csql.sqlcolumn, "!") {
|
||
return nil
|
||
}
|
||
columns, err := thos.getcolumn(csql)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
csql.sqlcolumn = strings.TrimLeft(csql.sqlcolumn, "!")
|
||
|
||
fields := strings.Split(csql.sqlcolumn, ",")
|
||
excludedFields := make(map[string]bool)
|
||
for _, field := range fields {
|
||
excludedFields[strings.TrimSpace(field)] = true
|
||
}
|
||
var filteredColumns []string
|
||
for _, column := range columns {
|
||
if !excludedFields[column] {
|
||
filteredColumns = append(filteredColumns, column)
|
||
}
|
||
}
|
||
csql.sqlcolumn = strings.Join(filteredColumns, ",")
|
||
return nil
|
||
}
|
||
|
||
// 错误err,没有数据返回正常空数组
|
||
func (thos *CiyMysql) Get(csql *CiySQL, argrowcount ...int) ([]map[string]any, int, error) {
|
||
var err error
|
||
rowcount := -1
|
||
if len(argrowcount) > 0 {
|
||
rowcount = argrowcount[0]
|
||
}
|
||
sqlstr := csql.rawsql
|
||
if sqlstr == "" {
|
||
err = thos.calcolumn(csql)
|
||
if err != nil {
|
||
thos.addError("Get.calcolumn", err)
|
||
return nil, -1, err
|
||
}
|
||
sqlstr, _ = csql.Buildsql(csql.sqlcolumn)
|
||
limit := csql.sqllimit
|
||
if thos.Tx != nil {
|
||
limit += " for update"
|
||
}
|
||
sqlstr += limit
|
||
}
|
||
csql.LastSQL = sqlstr
|
||
var rows *sql.Rows
|
||
if thos.Tx != nil {
|
||
rows, err = thos.Tx.Query(sqlstr, csql.tsmt...)
|
||
} else {
|
||
rows, err = thos.Db.Query(sqlstr, csql.tsmt...)
|
||
}
|
||
if err != nil {
|
||
thos.addError("Get.Query", err)
|
||
return nil, -1, err
|
||
}
|
||
defer rows.Close()
|
||
columns, err := rows.Columns()
|
||
if err != nil {
|
||
thos.addError("Get.Columns", err)
|
||
return nil, -1, err
|
||
}
|
||
scanArgs := make([]any, len(columns))
|
||
values := make([]any, len(columns))
|
||
for i := range values {
|
||
scanArgs[i] = &values[i]
|
||
}
|
||
ret := make([]map[string]any, 0)
|
||
for rows.Next() {
|
||
err := rows.Scan(scanArgs...)
|
||
if err != nil {
|
||
thos.addError("Get.Scan", err)
|
||
return nil, -1, err
|
||
}
|
||
record := make(map[string]any, len(columns))
|
||
for i, col := range values {
|
||
if col != nil {
|
||
switch col := col.(type) {
|
||
case []byte:
|
||
record[columns[i]] = string(col)
|
||
default:
|
||
record[columns[i]] = col
|
||
}
|
||
} else {
|
||
record[columns[i]] = ""
|
||
}
|
||
}
|
||
ret = append(ret, record)
|
||
}
|
||
if csql.rawsql == "" {
|
||
if rowcount == -1 {
|
||
sqlstr, _ := csql.Buildsql("count(*)")
|
||
row := thos.Db.QueryRow(sqlstr, csql.tsmt...)
|
||
if err := row.Err(); err != nil {
|
||
thos.addError("Get.count.QueryRow", err)
|
||
return ret, -1, err
|
||
}
|
||
var value any
|
||
err := row.Scan(&value)
|
||
if err != nil {
|
||
thos.addError("Get.count.Scan", err)
|
||
return ret, -1, err
|
||
}
|
||
return ret, Toint(value), nil
|
||
}
|
||
}
|
||
return ret, rowcount, nil
|
||
}
|
||
func (thos *CiyMysql) Getraw(sqlstr string) ([]map[string]any, error) {
|
||
var err error
|
||
var rows *sql.Rows
|
||
if thos.Tx != nil {
|
||
rows, err = thos.Tx.Query(sqlstr)
|
||
} else {
|
||
rows, err = thos.Db.Query(sqlstr)
|
||
}
|
||
if err != nil {
|
||
thos.addError("Get.Query", err)
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
columns, err := rows.Columns()
|
||
if err != nil {
|
||
thos.addError("Get.Columns", err)
|
||
return nil, err
|
||
}
|
||
scanArgs := make([]any, len(columns))
|
||
values := make([]any, len(columns))
|
||
for i := range values {
|
||
scanArgs[i] = &values[i]
|
||
}
|
||
ret := make([]map[string]any, 0)
|
||
for rows.Next() {
|
||
err := rows.Scan(scanArgs...)
|
||
if err != nil {
|
||
thos.addError("Get.Scan", err)
|
||
return nil, err
|
||
}
|
||
record := make(map[string]any, len(columns))
|
||
for i, col := range values {
|
||
if col != nil {
|
||
switch col := col.(type) {
|
||
case []byte:
|
||
record[columns[i]] = string(col)
|
||
default:
|
||
record[columns[i]] = col
|
||
}
|
||
} else {
|
||
record[columns[i]] = ""
|
||
}
|
||
}
|
||
ret = append(ret, record)
|
||
}
|
||
return ret, nil
|
||
}
|
||
func (thos *CiyMysql) GetField(csql *CiySQL) (map[string]map[string]any, string) {
|
||
retfield := map[string]map[string]any{}
|
||
fshow := ""
|
||
rowsfield, err := thos.Db.Query("show full fields from " + csql.table)
|
||
if err != nil {
|
||
thos.addError("GetField.Query", err)
|
||
return retfield, fshow
|
||
}
|
||
defer rowsfield.Close()
|
||
columns, err := rowsfield.Columns()
|
||
if err != nil {
|
||
thos.addError("GetField.Columns", err)
|
||
return retfield, fshow
|
||
}
|
||
scanArgs := make([]any, len(columns))
|
||
values := make([]any, len(columns))
|
||
for i := range values {
|
||
scanArgs[i] = &values[i]
|
||
}
|
||
for rowsfield.Next() {
|
||
err := rowsfield.Scan(scanArgs...)
|
||
if err != nil {
|
||
thos.addError("GetField.Scan", err)
|
||
return retfield, fshow
|
||
}
|
||
field := ""
|
||
var comment string
|
||
for i, col := range values {
|
||
if columns[i] == "Field" {
|
||
field = string(col.([]byte))
|
||
}
|
||
if columns[i] == "Comment" {
|
||
comment = string(col.([]byte))
|
||
}
|
||
}
|
||
if field != "" {
|
||
if comment != "" && !strings.HasPrefix(comment, ",") {
|
||
fshow += field + ","
|
||
}
|
||
retfield[field] = map[string]any{"c": comment}
|
||
}
|
||
}
|
||
return retfield, strings.TrimRight(fshow, ",")
|
||
}
|
||
func (thos *CiyMysql) Getdbcodes(table, column string) []map[string]any {
|
||
ret := make([]map[string]any, 0)
|
||
rows, err := thos.Db.Query("show full fields from "+table+" where Field=?", column)
|
||
if err != nil {
|
||
thos.addError("Getdbcodes.Query", err)
|
||
return ret
|
||
}
|
||
defer rows.Close()
|
||
columns, err := rows.Columns()
|
||
if err != nil {
|
||
thos.addError("Getdbcodes.Columns", err)
|
||
return ret
|
||
}
|
||
scanArgs := make([]any, len(columns))
|
||
values := make([]any, len(columns))
|
||
for i := range values {
|
||
scanArgs[i] = &values[i]
|
||
}
|
||
for rows.Next() {
|
||
err := rows.Scan(scanArgs...)
|
||
if err != nil {
|
||
thos.addError("Getdbcodes.Scan", err)
|
||
return ret
|
||
}
|
||
var comment string
|
||
for i, col := range values {
|
||
if columns[i] == "Comment" {
|
||
comment = string(col.([]byte))
|
||
}
|
||
}
|
||
if comment != "" {
|
||
ind := strings.Index(comment, ",TINT")
|
||
if ind == -1 {
|
||
ind = strings.Index(comment, ",TBIN")
|
||
}
|
||
if ind == -1 {
|
||
ind = strings.Index(comment, ",BOOL")
|
||
}
|
||
if ind == -1 {
|
||
return ret
|
||
}
|
||
exts := strings.Split(comment[ind+5:], ",")
|
||
for i, ext := range exts {
|
||
excos := strings.Split(ext, ".")
|
||
if len(excos) > 1 {
|
||
ret = append(ret, map[string]any{"id": excos[0], "name": excos[1]})
|
||
} else if len(excos[0]) > 0 {
|
||
ret = append(ret, map[string]any{"id": i, "name": excos[0]})
|
||
}
|
||
}
|
||
if strings.Contains(comment, ",BOOL") {
|
||
if len(ret) == 0 {
|
||
ret = append(ret, map[string]any{"id": "1", "name": "✔"})
|
||
}
|
||
if len(ret) == 1 {
|
||
ret = append(ret, map[string]any{"id": "2", "name": "✘"})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return ret
|
||
}
|
||
|
||
// 错误err,没有数据返回err,只有有数据正常
|
||
func (thos *CiyMysql) Getone(csql *CiySQL) (map[string]any, error) {
|
||
var err error
|
||
sqlstr := csql.rawsql
|
||
if sqlstr == "" {
|
||
err = thos.calcolumn(csql)
|
||
if err != nil {
|
||
thos.addError("Getone.calcolumn", err)
|
||
return nil, err
|
||
}
|
||
sqlstr, _ = csql.Buildsql(csql.sqlcolumn)
|
||
limit := " limit 0,1"
|
||
if thos.Tx != nil {
|
||
limit += " for update"
|
||
}
|
||
sqlstr += limit
|
||
}
|
||
csql.LastSQL = sqlstr
|
||
var rows *sql.Rows
|
||
if thos.Tx != nil {
|
||
rows, err = thos.Tx.Query(sqlstr, csql.tsmt...)
|
||
} else {
|
||
rows, err = thos.Db.Query(sqlstr, csql.tsmt...)
|
||
}
|
||
if err != nil {
|
||
thos.addError("Getone.Query", err)
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
columns, err := rows.Columns()
|
||
if err != nil {
|
||
thos.addError("Getone.Columns", err)
|
||
return nil, err
|
||
}
|
||
scanArgs := make([]any, len(columns))
|
||
values := make([]any, len(columns))
|
||
for i := range values {
|
||
scanArgs[i] = &values[i]
|
||
}
|
||
bdat := rows.Next()
|
||
if !bdat {
|
||
return nil, nil
|
||
}
|
||
err = rows.Scan(scanArgs...)
|
||
if err != nil {
|
||
thos.addError("Getone.Scan", err)
|
||
return nil, err
|
||
}
|
||
record := make(map[string]any, len(columns))
|
||
for i, col := range values {
|
||
if col != nil {
|
||
switch col := col.(type) {
|
||
case []byte:
|
||
record[columns[i]] = string(col)
|
||
default:
|
||
record[columns[i]] = col
|
||
}
|
||
} else {
|
||
record[columns[i]] = ""
|
||
}
|
||
}
|
||
return record, nil
|
||
}
|
||
|
||
// 无数据和错误都返回"",通过.Error判断
|
||
func (thos *CiyMysql) Get1(csql *CiySQL) any {
|
||
var err error
|
||
sqlstr := csql.rawsql
|
||
if sqlstr == "" {
|
||
col := csql.sqlcolumn
|
||
if col == "" || col == "*" || col[0] == '!' {
|
||
col = "count(*)"
|
||
}
|
||
var column string
|
||
sqlstr, column = csql.Buildsql(col)
|
||
limit := csql.sqllimit
|
||
if limit == "" && !strings.Contains(column, "(") {
|
||
limit = " limit 0,1"
|
||
}
|
||
if thos.Tx != nil {
|
||
limit += " for update"
|
||
}
|
||
sqlstr += limit
|
||
}
|
||
|
||
csql.LastSQL = sqlstr
|
||
var row *sql.Row
|
||
if thos.Tx != nil {
|
||
row = thos.Tx.QueryRow(sqlstr, csql.tsmt...)
|
||
} else {
|
||
row = thos.Db.QueryRow(sqlstr, csql.tsmt...)
|
||
}
|
||
if err := row.Err(); err != nil {
|
||
thos.addError("Get1.QueryRow", err)
|
||
return ""
|
||
}
|
||
var value any
|
||
err = row.Scan(&value)
|
||
if err != nil {
|
||
thos.addError("Get1.Scan", err)
|
||
return ""
|
||
}
|
||
if value == nil {
|
||
return ""
|
||
}
|
||
return value
|
||
}
|