Golang实践录:查询数据表的几种方式

Golang实践录:查询数据表的几种方式,第1张

本文汇总一些工程中使用到的查询数据表的代码示例。由于是代码片段,不一定保证完整。但其思想可以参考。

问题提出

工程中经常要使用到数据表(工作多年,不可避免沦为了CRUD工具人),打交道最多的是查询,对于插入更新接触比较少,由于所涉及的数据表是生产环境的,所以不敢越雷池半步。

golangsql包虽然没有包含数据库驱动,但在语言级别统一了接口,所以使用上还是有一定的便利之处。之前用golang写的一个内部工具,需要使用到mysql、oraclass="superseo">cle、sqlite3三种不同的数据库,就是看上golang的这个特点。
然而有时数据表字段实在太多了,而很多表的处理方法是一样的,如果均一一编写,则略显繁琐。本文综合一些资料,根据经验,汇总了几种查询数据表的方式。

解决方案 方案一:指定字段变量
func GetIntervalDetail_inner(sqldb *sql.DB, version string) (rets []conf.TestInfo) {
	sqlstr := fmt.Sprintf("select * from TestTable a where a.version = '%v' order by a.ID", version)
	// klog.Println("sqlstr: ", sqlstr)
	results, err := sqldb.Query(sqlstr)
	if err != nil {
		klog.Printf("Query error: %s\n", err.Error())
		return
	}

	for results.Next() {
		var item1, item2, item3, item4, item5, item7, item9, item10 sql.NullString
		var item6, item8 int

		err := results.Scan(&item1, &item2, &item3, &item4, &item5,
			&item6, &item7, &item8, &item9, &item10)
		if err != nil {
			klog.Println("scan error: ", err)
			break
		}
		// item7 有空格,先去掉
		item7.String = strings.TrimSpace(item7.String)
		if item7.String == "" {
			item7.String = "none"
		}

		var tmp conf.TestInfo
		tmp.Version = item1.String
		tmp.Code = item2.String
		tmp.ID = item3.String
		tmp.Code1 = item4.String
		tmp.Code2 = item5.String
		tmp.Length = item6
		tmp.F1_CODE = item7.String
		tmp.F1_length = item8
		tmp.F2_CODE = item9.String
		tmp.F2_length = item10.String

		rets = append(rets, tmp)
	}

	return
}

即使用到结构体,其本质也没有发生变化

func GetSpecialFee_inner(sqldb *sql.DB, Version string) (rets []conf.MySpeedRate) {
	sqlstr := fmt.Sprintf("select * from FoobarTable where Version=%v", Version)
	// klog.Println("sqlstr: ", sqlstr)
	results, err := sqldb.Query(sqlstr)
	if err != nil {
		klog.Printf("Query error: %s\n", err.Error())
		return
	}

	for results.Next() {
		var data conf.MySpeedRate
		err := results.Scan(&data.Version, &data.Rate[0], &data.Rate[1],
			&data.Rate[2], &data.Rate[3], &data.Rate[4], &data.Rate[5], &data.Rate[6], &data.Rate[7],
			&data.Rate[8], &data.Rate[9], &data.Rate[10], &data.Rate[11], &data.Rate[12], &data.Rate[13],
			&data.Rate[14], &data.Rate[15])
		if err != nil {
			klog.Println("scan error: ", err)
			break
		}
		rets = append(rets, data)
	}

	return
}
方案二:泛化:结构体
func GetAllRowsPtr(sqldb *sql.DB, query string, strname interface{}) (*[]interface{}, error) {
	result := make([]interface{}, 0)

	rows, err := sqldb.Query(query)
	if err != nil {
		return &result, err
	}
	defer rows.Close()

	s := reflect.ValueOf(strname).Elem()
	leng := s.NumField()
	scans := make([]interface{}, leng)
	for i := 0; i < leng; i++ {
		scans[i] = s.Field(i).Addr().Interface()
	}
	for rows.Next() {
		err = rows.Scan(scans...)
		if err != nil {
			panic(err)
		}
		result = append(result, s.Interface())
	}

	return &result, nil
}
方案三:泛化:字符串数组
func GetAllRowsString(sqldb *sql.DB, query string) ([]string, error) {
	rows, err := sqldb.Query(query)
	if err != nil {
		return []string{}, err
	}
	defer rows.Close()

	var results []string
	var tmp string

	// 获取字段名称
	tmp = ""
	cols, _ := rows.Columns()
	for i := range cols {
		tmp += cols[i] + ","
	}
	results = append(results, tmp)

	// 根据字段数量,指定查询scan的参数
	values := make([]sql.RawBytes, len(cols))
	scans := make([]interface{}, len(cols))
	for i := range values {
		scans[i] = &values[i]
	}

	for rows.Next() {
		if err := rows.Scan(scans...); err != nil {
			fmt.Println("Error")
			return []string{}, err
		}
		// 组装,暂定以逗号隔开
		tmp = ""
		for j := range values {
			tmp += string(values[j]) + ","
		}
		results = append(results, tmp)
	}

	return results, nil
}
小结

方案一是将数据表映射到结构体中,因此需要定义对应的结构体,但可以与数据表不一一对应,即根据sql语句只查询个别字段并赋值,如果不嫌麻烦,或者结构体随处需要使用,则可用此法。

方案二不需要定义结构体,实际使用的是接口,使用时需指定字段名称。实现代码中,如果查询的数据表字段和总字段不匹配,会提示panic: sql: expected 19 destination arguments in Scan, not 4

方案三在方案二基础上进行修改。会自动匹配查询sql的字段。最终组装成csv格式字符串数组。

不同方案均有优劣,按需使用即可。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/990383.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存