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 }