funcQueryHelperOne(db*sql.DB,resultinterface{},querystring,args...interface{})(errerror){// 数据库查询
varrows*sql.Rowslog.Debug(query,args)rows,err=db.Query(query,args...)iferr!=nil{returnerr}deferrows.Close()// 获取列名称,并转换首字母大写,用于和struct Field 匹配
varcolumns[]stringcolumns,err=rows.Columns()iferr!=nil{returnerr}fields:=make([]string,len(columns))fori,columnName:=rangecolumns{fields[i]=server.firstCharToUpper(columnName)}// 传参必须是数组 slice 指针
rv:=reflect.ValueOf(result)ifrv.Kind()==reflect.Ptr{rv=rv.Elem()}else{returnerrors.New("Parameter result must be a slice pointer")}ifrv.Kind()==reflect.Slice{elemType:=rv.Type().Elem()ifelemType.Kind()==reflect.Struct{ev:=reflect.New(elemType)// 申请slice 数据,之后赋值给result
nv:=reflect.MakeSlice(rv.Type(),0,0)ignoreData:=make([][]byte,len(columns))forrows.Next(){// for each rows
// scanArgs 是扫描每行数据的参数
// scanArgs 中存储的是 struct 中field 的指针
scanArgs:=make([]interface{},len(fields))fori,fieldName:=rangefields{fv:=ev.Elem().FieldByName(fieldName)iffv.Kind()!=reflect.Invalid{scanArgs[i]=fv.Addr().Interface()}else{ignoreData[i]=[]byte{}scanArgs[i]=&ignoreData[i]}}err=rows.Scan(scanArgs...)iferr!=nil{returnerr}nv=reflect.Append(nv,ev.Elem())}rv.Set(nv)}}else{returnerrors.New("Parameter result must be a slice pointer")}return}
// 定义数据池,用于存储每个sql 对应的扫描行item 以及扫描参数
// 全局代码
vardatapools=sync.Map{}typeReflectItemstruct{Itemreflect.ValuescanArgs[]interface{}}///////// 方法调用内部
// 从数据池中加载query 对应的 ReflectItem
ifv,ok:=datapools.Load(query);ok{pool=v.(*sync.Pool)}else{// 构建reflectItem
varcolumns[]stringcolumns,err=rows.Columns()iferr!=nil{returnerr}pool=&sync.Pool{New:func()interface{}{fields:=make([]string,len(columns))fori,columnName:=rangecolumns{fields[i]=server.firstCharToUpper(columnName)}ev:=reflect.New(elemType)// New slice struct element
// nv := reflect.MakeSlice(rv.Type(), 0, 0) // New slice for fill
ignored:=[]byte{}scanArgs:=make([]interface{},len(fields))fori,fieldName:=rangefields{fv:=ev.Elem().FieldByName(fieldName)iffv.Kind()!=reflect.Invalid{scanArgs[i]=fv.Addr().Interface()}else{scanArgs[i]=&ignored}}returnReflectItem{Item:ev,scanArgs:scanArgs,}},}datapools.Store(query,pool)}ri=pool.Get().(ReflectItem)// 复用 ev 和 scanArgs
ev=ri.ItemscanArgs=ri.scanArgs// 开始扫描
nv:=rv.Slice(0,0)forrows.Next(){// for each rows
err=rows.Scan(scanArgs...)iferr!=nil{returnerr}nv=reflect.Append(nv,ev.Elem())}rv.Set(nv)// return rows data back to caller
pool.Put(ri)// 结束扫描