github.com/zhongdalu/gf@v1.0.0/g/database/gdb/gdb_base.go (about)

     1  // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/zhongdalu/gf.
     6  //
     7  
     8  package gdb
     9  
    10  import (
    11  	"bytes"
    12  	"database/sql"
    13  	"errors"
    14  	"fmt"
    15  	"reflect"
    16  	"regexp"
    17  	"strings"
    18  
    19  	"github.com/zhongdalu/gf/g/text/gstr"
    20  
    21  	"github.com/zhongdalu/gf/g/container/gvar"
    22  	"github.com/zhongdalu/gf/g/os/gcache"
    23  	"github.com/zhongdalu/gf/g/os/gtime"
    24  	"github.com/zhongdalu/gf/g/text/gregex"
    25  	"github.com/zhongdalu/gf/g/util/gconv"
    26  )
    27  
    28  const (
    29  	// 默认调试模式下记录的SQL条数
    30  	gDEFAULT_DEBUG_SQL_LENGTH = 1000
    31  )
    32  
    33  var (
    34  	wordReg         = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
    35  	lastOperatorReg = regexp.MustCompile(`[<>=]+\s*$`)
    36  )
    37  
    38  // 获取最近一条执行的sql
    39  func (bs *dbBase) GetLastSql() *Sql {
    40  	if bs.sqls == nil {
    41  		return nil
    42  	}
    43  	if v := bs.sqls.Val(); v != nil {
    44  		return v.(*Sql)
    45  	}
    46  	return nil
    47  }
    48  
    49  // 获取已经执行的SQL列表(仅在debug=true时有效)
    50  func (bs *dbBase) GetQueriedSqls() []*Sql {
    51  	if bs.sqls == nil {
    52  		return nil
    53  	}
    54  	sqls := make([]*Sql, 0)
    55  	bs.sqls.Prev()
    56  	bs.sqls.RLockIteratorPrev(func(value interface{}) bool {
    57  		if value == nil {
    58  			return false
    59  		}
    60  		sqls = append(sqls, value.(*Sql))
    61  		return true
    62  	})
    63  	return sqls
    64  }
    65  
    66  // 打印已经执行的SQL列表(仅在debug=true时有效)
    67  func (bs *dbBase) PrintQueriedSqls() {
    68  	sqls := bs.GetQueriedSqls()
    69  	for k, v := range sqls {
    70  		fmt.Println(len(sqls)-k, ":")
    71  		fmt.Println("    Sql  :", v.Sql)
    72  		fmt.Println("    Args :", v.Args)
    73  		fmt.Println("    Error:", v.Error)
    74  		fmt.Println("    Start:", gtime.NewFromTimeStamp(v.Start).Format("Y-m-d H:i:s.u"))
    75  		fmt.Println("    End  :", gtime.NewFromTimeStamp(v.End).Format("Y-m-d H:i:s.u"))
    76  		fmt.Println("    Cost :", v.End-v.Start, "ms")
    77  	}
    78  }
    79  
    80  // 数据库sql查询操作,主要执行查询
    81  func (bs *dbBase) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
    82  	link, err := bs.db.Slave()
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	return bs.db.doQuery(link, query, args...)
    87  }
    88  
    89  // 数据库sql查询操作,主要执行查询
    90  func (bs *dbBase) doQuery(link dbLink, query string, args ...interface{}) (rows *sql.Rows, err error) {
    91  	query, args = formatQuery(query, args)
    92  	query = bs.db.handleSqlBeforeExec(query)
    93  	if bs.db.getDebug() {
    94  		mTime1 := gtime.Millisecond()
    95  		rows, err = link.Query(query, args...)
    96  		mTime2 := gtime.Millisecond()
    97  		s := &Sql{
    98  			Sql:   query,
    99  			Args:  args,
   100  			Error: err,
   101  			Start: mTime1,
   102  			End:   mTime2,
   103  		}
   104  		bs.sqls.Put(s)
   105  		printSql(s)
   106  	} else {
   107  		rows, err = link.Query(query, args...)
   108  	}
   109  	if err == nil {
   110  		return rows, nil
   111  	} else {
   112  		err = formatError(err, query, args...)
   113  	}
   114  	return nil, err
   115  }
   116  
   117  // 执行一条sql,并返回执行情况,主要用于非查询操作
   118  func (bs *dbBase) Exec(query string, args ...interface{}) (result sql.Result, err error) {
   119  	link, err := bs.db.Master()
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	return bs.db.doExec(link, query, args...)
   124  }
   125  
   126  // 执行一条sql,并返回执行情况,主要用于非查询操作
   127  func (bs *dbBase) doExec(link dbLink, query string, args ...interface{}) (result sql.Result, err error) {
   128  	query, args = formatQuery(query, args)
   129  	query = bs.db.handleSqlBeforeExec(query)
   130  	if bs.db.getDebug() {
   131  		mTime1 := gtime.Millisecond()
   132  		result, err = link.Exec(query, args...)
   133  		mTime2 := gtime.Millisecond()
   134  		s := &Sql{
   135  			Sql:   query,
   136  			Args:  args,
   137  			Error: err,
   138  			Start: mTime1,
   139  			End:   mTime2,
   140  		}
   141  		bs.sqls.Put(s)
   142  		printSql(s)
   143  	} else {
   144  		result, err = link.Exec(query, args...)
   145  	}
   146  	return result, formatError(err, query, args...)
   147  }
   148  
   149  // SQL预处理,执行完成后调用返回值sql.Stmt.Exec完成sql操作; 默认执行在Slave上, 通过第二个参数指定执行在Master上
   150  func (bs *dbBase) Prepare(query string, execOnMaster ...bool) (*sql.Stmt, error) {
   151  	err := (error)(nil)
   152  	link := (dbLink)(nil)
   153  	if len(execOnMaster) > 0 && execOnMaster[0] {
   154  		if link, err = bs.db.Master(); err != nil {
   155  			return nil, err
   156  		}
   157  	} else {
   158  		if link, err = bs.db.Slave(); err != nil {
   159  			return nil, err
   160  		}
   161  	}
   162  	return bs.db.doPrepare(link, query)
   163  }
   164  
   165  // SQL预处理,执行完成后调用返回值sql.Stmt.Exec完成sql操作
   166  func (bs *dbBase) doPrepare(link dbLink, query string) (*sql.Stmt, error) {
   167  	return link.Prepare(query)
   168  }
   169  
   170  // 数据库查询,获取查询结果集,以列表结构返回
   171  func (bs *dbBase) GetAll(query string, args ...interface{}) (Result, error) {
   172  	rows, err := bs.Query(query, args...)
   173  	if err != nil || rows == nil {
   174  		return nil, err
   175  	}
   176  	defer rows.Close()
   177  	return bs.db.rowsToResult(rows)
   178  }
   179  
   180  // 数据库查询,获取查询结果记录,以关联数组结构返回
   181  func (bs *dbBase) GetOne(query string, args ...interface{}) (Record, error) {
   182  	list, err := bs.GetAll(query, args...)
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  	if len(list) > 0 {
   187  		return list[0], nil
   188  	}
   189  	return nil, nil
   190  }
   191  
   192  // 数据库查询,查询单条记录,自动映射数据到给定的struct对象中
   193  func (bs *dbBase) GetStruct(pointer interface{}, query string, args ...interface{}) error {
   194  	one, err := bs.GetOne(query, args...)
   195  	if err != nil {
   196  		return err
   197  	}
   198  	return one.ToStruct(pointer)
   199  }
   200  
   201  // 数据库查询,查询多条记录,并自动转换为指定的slice对象, 如: []struct/[]*struct。
   202  func (bs *dbBase) GetStructs(pointer interface{}, query string, args ...interface{}) error {
   203  	all, err := bs.GetAll(query, args...)
   204  	if err != nil {
   205  		return err
   206  	}
   207  	return all.ToStructs(pointer)
   208  }
   209  
   210  // 将结果转换为指定的struct/*struct/[]struct/[]*struct,
   211  // 参数应该为指针类型,否则返回失败。
   212  // 该方法自动识别参数类型,调用Struct/Structs方法。
   213  func (bs *dbBase) GetScan(pointer interface{}, query string, args ...interface{}) error {
   214  	t := reflect.TypeOf(pointer)
   215  	k := t.Kind()
   216  	if k != reflect.Ptr {
   217  		return fmt.Errorf("params should be type of pointer, but got: %v", k)
   218  	}
   219  	k = t.Elem().Kind()
   220  	switch k {
   221  	case reflect.Array, reflect.Slice:
   222  		return bs.db.GetStructs(pointer, query, args...)
   223  	case reflect.Struct:
   224  		return bs.db.GetStruct(pointer, query, args...)
   225  	}
   226  	return fmt.Errorf("element type should be type of struct/slice, unsupported: %v", k)
   227  }
   228  
   229  // 数据库查询,获取查询字段值
   230  func (bs *dbBase) GetValue(query string, args ...interface{}) (Value, error) {
   231  	one, err := bs.GetOne(query, args...)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	for _, v := range one {
   236  		return v, nil
   237  	}
   238  	return nil, nil
   239  }
   240  
   241  // 数据库查询,获取查询数量
   242  func (bs *dbBase) GetCount(query string, args ...interface{}) (int, error) {
   243  	if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, query) {
   244  		query, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, query)
   245  	}
   246  	value, err := bs.GetValue(query, args...)
   247  	if err != nil {
   248  		return 0, err
   249  	}
   250  	return value.Int(), nil
   251  }
   252  
   253  // ping一下,判断或保持数据库链接(master)
   254  func (bs *dbBase) PingMaster() error {
   255  	if master, err := bs.db.Master(); err != nil {
   256  		return err
   257  	} else {
   258  		return master.Ping()
   259  	}
   260  }
   261  
   262  // ping一下,判断或保持数据库链接(slave)
   263  func (bs *dbBase) PingSlave() error {
   264  	if slave, err := bs.db.Slave(); err != nil {
   265  		return err
   266  	} else {
   267  		return slave.Ping()
   268  	}
   269  }
   270  
   271  // 事务操作,开启,会返回一个底层的事务操作对象链接如需要嵌套事务,那么可以使用该对象,否则请忽略
   272  // 只有在tx.Commit/tx.Rollback时,链接会自动Close
   273  func (bs *dbBase) Begin() (*TX, error) {
   274  	if master, err := bs.db.Master(); err != nil {
   275  		return nil, err
   276  	} else {
   277  		if tx, err := master.Begin(); err == nil {
   278  			return &TX{
   279  				db:     bs.db,
   280  				tx:     tx,
   281  				master: master,
   282  			}, nil
   283  		} else {
   284  			return nil, err
   285  		}
   286  	}
   287  }
   288  
   289  // CURD操作:单条数据写入, 仅仅执行写入操作,如果存在冲突的主键或者唯一索引,那么报错返回。
   290  // 参数data支持map/struct/*struct/slice类型,
   291  // 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
   292  func (bs *dbBase) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
   293  	return bs.db.doInsert(nil, table, data, OPTION_INSERT, batch...)
   294  }
   295  
   296  // CURD操作:单条数据写入, 如果数据存在(主键或者唯一索引),那么删除后重新写入一条。
   297  // 参数data支持map/struct/*struct/slice类型,
   298  // 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
   299  func (bs *dbBase) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
   300  	return bs.db.doInsert(nil, table, data, OPTION_REPLACE, batch...)
   301  }
   302  
   303  // CURD操作:单条数据写入, 如果数据存在(主键或者唯一索引),那么更新,否则写入一条新数据。
   304  // 参数data支持map/struct/*struct/slice类型,
   305  // 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
   306  func (bs *dbBase) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
   307  	return bs.db.doInsert(nil, table, data, OPTION_SAVE, batch...)
   308  }
   309  
   310  // 支持insert、replace, save, ignore操作。
   311  // 0: insert:  仅仅执行写入操作,如果存在冲突的主键或者唯一索引,那么报错返回;
   312  // 1: replace: 如果数据存在(主键或者唯一索引),那么删除后重新写入一条;
   313  // 2: save:    如果数据存在(主键或者唯一索引),那么更新,否则写入一条新数据;
   314  // 3: ignore:  如果数据存在(主键或者唯一索引),那么什么也不做;
   315  //
   316  // 参数data支持map/struct/*struct/slice类型,
   317  // 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
   318  func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option int, batch ...int) (result sql.Result, err error) {
   319  	var fields []string
   320  	var values []string
   321  	var params []interface{}
   322  	var dataMap Map
   323  	table = bs.db.quoteWord(table)
   324  	// 使用反射判断data数据类型,如果为slice类型,那么自动转为批量操作
   325  	rv := reflect.ValueOf(data)
   326  	kind := rv.Kind()
   327  	if kind == reflect.Ptr {
   328  		rv = rv.Elem()
   329  		kind = rv.Kind()
   330  	}
   331  	switch kind {
   332  	case reflect.Slice:
   333  		fallthrough
   334  	case reflect.Array:
   335  		return bs.db.doBatchInsert(link, table, data, option, batch...)
   336  	case reflect.Map:
   337  		fallthrough
   338  	case reflect.Struct:
   339  		dataMap = structToMap(data)
   340  	default:
   341  		return result, errors.New(fmt.Sprint("unsupported data type:", kind))
   342  	}
   343  	charL, charR := bs.db.getChars()
   344  	for k, v := range dataMap {
   345  		fields = append(fields, charL+k+charR)
   346  		values = append(values, "?")
   347  		params = append(params, convertParam(v))
   348  	}
   349  	operation := getInsertOperationByOption(option)
   350  	updateStr := ""
   351  	if option == OPTION_SAVE {
   352  		for k, _ := range dataMap {
   353  			if len(updateStr) > 0 {
   354  				updateStr += ","
   355  			}
   356  			updateStr += fmt.Sprintf("%s%s%s=VALUES(%s%s%s)",
   357  				charL, k, charR,
   358  				charL, k, charR,
   359  			)
   360  		}
   361  		updateStr = fmt.Sprintf(" ON DUPLICATE KEY UPDATE %s", updateStr)
   362  	}
   363  	if link == nil {
   364  		if link, err = bs.db.Master(); err != nil {
   365  			return nil, err
   366  		}
   367  	}
   368  	return bs.db.doExec(link, fmt.Sprintf("%s INTO %s(%s) VALUES(%s) %s",
   369  		operation, table, strings.Join(fields, ","),
   370  		strings.Join(values, ","), updateStr),
   371  		params...)
   372  }
   373  
   374  // CURD操作:批量数据指定批次量写入
   375  func (bs *dbBase) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
   376  	return bs.db.doBatchInsert(nil, table, list, OPTION_INSERT, batch...)
   377  }
   378  
   379  // CURD操作:批量数据指定批次量写入, 如果数据存在(主键或者唯一索引),那么删除后重新写入一条
   380  func (bs *dbBase) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
   381  	return bs.db.doBatchInsert(nil, table, list, OPTION_REPLACE, batch...)
   382  }
   383  
   384  // CURD操作:批量数据指定批次量写入, 如果数据存在(主键或者唯一索引),那么更新,否则写入一条新数据
   385  func (bs *dbBase) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
   386  	return bs.db.doBatchInsert(nil, table, list, OPTION_SAVE, batch...)
   387  }
   388  
   389  // 批量写入数据, 参数list支持slice类型,例如: []map/[]struct/[]*struct。
   390  func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
   391  	var keys []string
   392  	var values []string
   393  	var params []interface{}
   394  	table = bs.db.quoteWord(table)
   395  	listMap := (List)(nil)
   396  	switch v := list.(type) {
   397  	case Result:
   398  		listMap = v.ToList()
   399  	case Record:
   400  		listMap = List{v.ToMap()}
   401  	case List:
   402  		listMap = v
   403  	case Map:
   404  		listMap = List{v}
   405  	default:
   406  		rv := reflect.ValueOf(list)
   407  		kind := rv.Kind()
   408  		if kind == reflect.Ptr {
   409  			rv = rv.Elem()
   410  			kind = rv.Kind()
   411  		}
   412  		switch kind {
   413  		// 如果是slice,那么转换为List类型
   414  		case reflect.Slice:
   415  			fallthrough
   416  		case reflect.Array:
   417  			listMap = make(List, rv.Len())
   418  			for i := 0; i < rv.Len(); i++ {
   419  				listMap[i] = structToMap(rv.Index(i).Interface())
   420  			}
   421  		case reflect.Map:
   422  			fallthrough
   423  		case reflect.Struct:
   424  			listMap = List{Map(structToMap(list))}
   425  		default:
   426  			return result, errors.New(fmt.Sprint("unsupported list type:", kind))
   427  		}
   428  	}
   429  	// 判断长度
   430  	if len(listMap) < 1 {
   431  		return result, errors.New("empty data list")
   432  	}
   433  	if link == nil {
   434  		if link, err = bs.db.Master(); err != nil {
   435  			return
   436  		}
   437  	}
   438  	// 首先获取字段名称及记录长度
   439  	holders := []string(nil)
   440  	for k, _ := range listMap[0] {
   441  		keys = append(keys, k)
   442  		holders = append(holders, "?")
   443  	}
   444  	batchResult := new(batchSqlResult)
   445  	charL, charR := bs.db.getChars()
   446  	keyStr := charL + strings.Join(keys, charR+","+charL) + charR
   447  	valueHolderStr := "(" + strings.Join(holders, ",") + ")"
   448  	// 操作判断
   449  	operation := getInsertOperationByOption(option)
   450  	updateStr := ""
   451  	if option == OPTION_SAVE {
   452  		for _, k := range keys {
   453  			if len(updateStr) > 0 {
   454  				updateStr += ","
   455  			}
   456  			updateStr += fmt.Sprintf("%s%s%s=VALUES(%s%s%s)",
   457  				charL, k, charR,
   458  				charL, k, charR,
   459  			)
   460  		}
   461  		updateStr = fmt.Sprintf(" ON DUPLICATE KEY UPDATE %s", updateStr)
   462  	}
   463  	// 构造批量写入数据格式(注意map的遍历是无序的)
   464  	batchNum := gDEFAULT_BATCH_NUM
   465  	if len(batch) > 0 {
   466  		batchNum = batch[0]
   467  	}
   468  	for i := 0; i < len(listMap); i++ {
   469  		for _, k := range keys {
   470  			params = append(params, convertParam(listMap[i][k]))
   471  		}
   472  		values = append(values, valueHolderStr)
   473  		if len(values) == batchNum {
   474  			r, err := bs.db.doExec(link, fmt.Sprintf("%s INTO %s(%s) VALUES%s %s",
   475  				operation, table, keyStr, strings.Join(values, ","),
   476  				updateStr),
   477  				params...)
   478  			if err != nil {
   479  				return r, err
   480  			}
   481  			if n, err := r.RowsAffected(); err != nil {
   482  				return r, err
   483  			} else {
   484  				batchResult.lastResult = r
   485  				batchResult.rowsAffected += n
   486  			}
   487  			params = params[:0]
   488  			values = values[:0]
   489  		}
   490  	}
   491  	// 处理最后不构成指定批量的数据
   492  	if len(values) > 0 {
   493  		r, err := bs.db.doExec(link, fmt.Sprintf("%s INTO %s(%s) VALUES%s %s",
   494  			operation, table, keyStr, strings.Join(values, ","),
   495  			updateStr),
   496  			params...)
   497  		if err != nil {
   498  			return r, err
   499  		}
   500  		if n, err := r.RowsAffected(); err != nil {
   501  			return r, err
   502  		} else {
   503  			batchResult.lastResult = r
   504  			batchResult.rowsAffected += n
   505  		}
   506  	}
   507  	return batchResult, nil
   508  }
   509  
   510  // CURD操作:数据更新,统一采用sql预处理。
   511  // data参数支持string/map/struct/*struct类型。
   512  func (bs *dbBase) Update(table string, data interface{}, condition interface{}, args ...interface{}) (sql.Result, error) {
   513  	newWhere, newArgs := bs.db.formatWhere(condition, args)
   514  	if newWhere != "" {
   515  		newWhere = " WHERE " + newWhere
   516  	}
   517  	return bs.db.doUpdate(nil, table, data, newWhere, newArgs...)
   518  }
   519  
   520  // CURD操作:数据更新,统一采用sql预处理。
   521  // data参数支持string/map/struct/*struct类型类型。
   522  func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) {
   523  	table = bs.db.quoteWord(table)
   524  	updates := ""
   525  	// 使用反射进行类型判断
   526  	rv := reflect.ValueOf(data)
   527  	kind := rv.Kind()
   528  	if kind == reflect.Ptr {
   529  		rv = rv.Elem()
   530  		kind = rv.Kind()
   531  	}
   532  	params := []interface{}(nil)
   533  	switch kind {
   534  	case reflect.Map:
   535  		fallthrough
   536  	case reflect.Struct:
   537  		var fields []string
   538  		for k, v := range structToMap(data) {
   539  			fields = append(fields, bs.db.quoteWord(k)+"=?")
   540  			params = append(params, convertParam(v))
   541  		}
   542  		updates = strings.Join(fields, ",")
   543  	default:
   544  		updates = gconv.String(data)
   545  	}
   546  	if len(params) > 0 {
   547  		args = append(params, args...)
   548  	}
   549  	// 如果没有传递link,那么使用默认的写库对象
   550  	if link == nil {
   551  		if link, err = bs.db.Master(); err != nil {
   552  			return nil, err
   553  		}
   554  	}
   555  	return bs.db.doExec(link, fmt.Sprintf("UPDATE %s SET %s%s", table, updates, condition), args...)
   556  }
   557  
   558  // CURD操作:删除数据
   559  func (bs *dbBase) Delete(table string, condition interface{}, args ...interface{}) (result sql.Result, err error) {
   560  	newWhere, newArgs := bs.db.formatWhere(condition, args)
   561  	if newWhere != "" {
   562  		newWhere = " WHERE " + newWhere
   563  	}
   564  	return bs.db.doDelete(nil, table, newWhere, newArgs...)
   565  }
   566  
   567  // CURD操作:删除数据
   568  func (bs *dbBase) doDelete(link dbLink, table string, condition string, args ...interface{}) (result sql.Result, err error) {
   569  	if link == nil {
   570  		if link, err = bs.db.Master(); err != nil {
   571  			return nil, err
   572  		}
   573  	}
   574  	table = bs.db.quoteWord(table)
   575  	return bs.db.doExec(link, fmt.Sprintf("DELETE FROM %s%s", table, condition), args...)
   576  }
   577  
   578  // 获得缓存对象
   579  func (bs *dbBase) getCache() *gcache.Cache {
   580  	return bs.cache
   581  }
   582  
   583  // 将数据查询的列表数据*sql.Rows转换为Result类型
   584  func (bs *dbBase) rowsToResult(rows *sql.Rows) (Result, error) {
   585  	if !rows.Next() {
   586  		return nil, sql.ErrNoRows
   587  	}
   588  	// 列信息列表, 名称与类型
   589  	columnTypes, err := rows.ColumnTypes()
   590  	if err != nil {
   591  		return nil, err
   592  	}
   593  	types := make([]string, len(columnTypes))
   594  	columns := make([]string, len(columnTypes))
   595  	for k, v := range columnTypes {
   596  		types[k] = v.DatabaseTypeName()
   597  		columns[k] = v.Name()
   598  	}
   599  	// 返回结构组装
   600  	values := make([]sql.RawBytes, len(columns))
   601  	scanArgs := make([]interface{}, len(values))
   602  	records := make(Result, 0)
   603  	for i := range values {
   604  		scanArgs[i] = &values[i]
   605  	}
   606  	for {
   607  		if err := rows.Scan(scanArgs...); err != nil {
   608  			return records, err
   609  		}
   610  		row := make(Record)
   611  		// 注意col字段是一个[]byte类型(slice类型本身是一个引用类型),
   612  		// 多个记录循环时该变量指向的是同一个内存地址
   613  		for i, column := range values {
   614  			if column == nil {
   615  				row[columns[i]] = gvar.New(nil, true)
   616  			} else {
   617  				// 由于 sql.RawBytes 是slice类型, 这里必须使用值复制
   618  				v := make([]byte, len(column))
   619  				copy(v, column)
   620  				//fmt.Println(columns[i], types[i], string(v), v, bs.db.convertValue(v, types[i]))
   621  				row[columns[i]] = gvar.New(bs.db.convertValue(v, types[i]), true)
   622  			}
   623  		}
   624  		records = append(records, row)
   625  		if !rows.Next() {
   626  			break
   627  		}
   628  	}
   629  	return records, nil
   630  }
   631  
   632  // 格式化Where查询条件。
   633  func (bs *dbBase) formatWhere(where interface{}, args []interface{}) (newWhere string, newArgs []interface{}) {
   634  	// 条件字符串处理
   635  	buffer := bytes.NewBuffer(nil)
   636  	// 使用反射进行类型判断
   637  	rv := reflect.ValueOf(where)
   638  	kind := rv.Kind()
   639  	if kind == reflect.Ptr {
   640  		rv = rv.Elem()
   641  		kind = rv.Kind()
   642  	}
   643  	switch kind {
   644  	// map/struct类型
   645  	case reflect.Map:
   646  		fallthrough
   647  	case reflect.Struct:
   648  		for key, value := range structToMap(where) {
   649  			// 字段安全符号判断
   650  			key = bs.db.quoteWord(key)
   651  			if buffer.Len() > 0 {
   652  				buffer.WriteString(" AND ")
   653  			}
   654  			// 支持slice键值/属性,如果只有一个?占位符号,那么作为IN查询,否则打散作为多个查询参数
   655  			rv := reflect.ValueOf(value)
   656  			switch rv.Kind() {
   657  			case reflect.Slice:
   658  				fallthrough
   659  			case reflect.Array:
   660  				count := gstr.Count(key, "?")
   661  				if count == 0 {
   662  					buffer.WriteString(key + " IN(?)")
   663  					newArgs = append(newArgs, value)
   664  				} else if count != rv.Len() {
   665  					buffer.WriteString(key)
   666  					newArgs = append(newArgs, value)
   667  				} else {
   668  					buffer.WriteString(key)
   669  					// 如果键名/属性名称中带有多个?占位符号,那么将参数打散
   670  					newArgs = append(newArgs, gconv.Interfaces(value)...)
   671  				}
   672  			default:
   673  				if value == nil {
   674  					buffer.WriteString(key)
   675  				} else {
   676  					// 支持key带操作符号
   677  					if gstr.Pos(key, "?") == -1 {
   678  						if gstr.Pos(key, "<") == -1 && gstr.Pos(key, ">") == -1 && gstr.Pos(key, "=") == -1 {
   679  							buffer.WriteString(key + "=?")
   680  						} else {
   681  							buffer.WriteString(key + "?")
   682  						}
   683  					} else {
   684  						buffer.WriteString(key)
   685  					}
   686  					newArgs = append(newArgs, value)
   687  				}
   688  			}
   689  		}
   690  
   691  	default:
   692  		buffer.WriteString(gconv.String(where))
   693  	}
   694  	// 没有任何条件查询参数,直接返回
   695  	if buffer.Len() == 0 {
   696  		return "", args
   697  	}
   698  	newArgs = append(newArgs, args...)
   699  	newWhere = buffer.String()
   700  	// 查询条件参数处理,主要处理slice参数类型
   701  	if len(newArgs) > 0 {
   702  		// 支持例如 Where/And/Or("uid", 1) , Where/And/Or("uid>=", 1) 这种格式
   703  		if gstr.Pos(newWhere, "?") == -1 {
   704  			if lastOperatorReg.MatchString(newWhere) {
   705  				newWhere += "?"
   706  			} else if wordReg.MatchString(newWhere) {
   707  				newWhere += "=?"
   708  			}
   709  		}
   710  	}
   711  	return
   712  }
   713  
   714  // 使用关键字操作符转义给定字符串。
   715  // 如果给定的字符串不为单词,那么不转义,直接返回该字符串。
   716  func (bs *dbBase) quoteWord(s string) string {
   717  	charLeft, charRight := bs.db.getChars()
   718  	if wordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
   719  		return charLeft + s + charRight
   720  	}
   721  	return s
   722  }
   723  
   724  // 动态切换数据库
   725  func (bs *dbBase) setSchema(sqlDb *sql.DB, schema string) error {
   726  	_, err := sqlDb.Exec("USE " + schema)
   727  	return err
   728  }