【巧妙】GO + MySQL的通用查询方法

 

GO语言与MySQL的结合还是比较容易的,像是连接,增、删、改这些操作都比较简单,唯独在查询的时候感觉比较坑(见代码),下面是官方推荐的标准查询方式:

var id int
var name string
var address string
rows, err := DB.Query("select id,name,address from users")
if err != nil {
   fmt.Println(err)
}
for rows.Next() {
   rows.Scan(&id, &name, &address)
   fmt.Println(id, name, address)
}
defer rows.Close()

这种正统的方法在执行SQL语句后,还需要通过rows.Scan()逐行读出数据,最关键的是还需要与咱的SQL语句配合好,语句里面查询了几个列,Scan这边就必须相应地用同样的独立变量与之一 一对应,否则就会报错。

查询功能是数据库应用中用得最频繁的,各种不同的表,列的数量和列名千差万别,按照上面这种查询模式,那么每一种查询那都得要重新写一个读取函数,感觉这非常浪费时间,因此,一种通用的可变列名和列数的查询方法就显得非常重要了。

以下是完整代码(我做了详细注释,很容易明白):

package mysql_con

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

var DB *sql.DB

func initDB() bool { //连接到MySQL
	path := "root:password@tcp(127.0.0.1:3306)/mydb?charset=utf8"
    //root = 用户名
    //password = 密码
    //mydb = 数据库名称

	fmt.Println(path)
	DB, _ = sql.Open("mysql", path)
	DB.SetConnMaxLifetime(100)
	DB.SetMaxIdleConns(10)
	//验证连接
	if err := DB.Ping(); err != nil {
		return false
	}
	return true
}

func Exec(SQL string) {
	if initDB() == true {
		ret, _ := DB.Exec(SQL) //增、删、改就靠这一条命令就够了,很简单
		insID, _ := ret.LastInsertId()
		fmt.Println(insID)
	}
}

func Query(SQL string) ([]map[string]string, bool) { //通用查询寒素
	if initDB() != true { //连接数据库
		return nil, false
	}
	rows, err := DB.Query(SQL) //执行SQL语句,比如select * from users
	if err != nil {
		panic(err)
	}
	columns, _ := rows.Columns()            //获取列的信息
	count := len(columns)                   //列的数量
	var values = make([]interface{}, count) //创建一个与列的数量相当的空接口
	for i, _ := range values {
		var ii interface{} //为空接口分配内存
		values[i] = &ii    //取得这些内存的指针,因后继的Scan函数只接受指针
	}
	ret := make([]map[string]string, 0) //创建返回值:不定长的map类型切片
	for rows.Next() {
		err := rows.Scan(values...)  //开始读行,Scan函数只接受指针变量
		m := make(map[string]string) //用于存放1列的 [键/值] 对
		if err != nil {
			panic(err)
		}
		for i, colName := range columns {
			var raw_value = *(values[i].(*interface{})) //读出raw数据,类型为byte
			b, _ := raw_value.([]byte)
			v := string(b) //将raw数据转换成字符串
			m[colName] = v //colName是键,v是值
		}
		ret = append(ret, m) //将单行所有列的键值对附加在总的返回值上(以行为单位)
	}
    
    defer rows.Close()

	if len(ret) != 0 {
		return ret, true
	}
	return nil, false
}

至此我们的通用Query查询函数就大功告成了,这个函数在使用起来也比较简单:

	rst, ok := mysql_con.Query("select * from users where id = 1") 
//rst是返回的记录集,ok表示是否查询成功,也可以用来判断是不是空查询
	if ok {
		fmt.Println(rst[0]["name"])
	} else {
		fmt.Println("没有找到数据")
	}

使用的时候就用rst[行] ["列名"]来读取数据即可,一个函数可以对付所有的场景,感觉非常巧妙!

PS:本文参阅了以下文章,并进行了一些小的改动:

https://stackoverflow.com/questions/17845619/how-to-call-the-scan-variadic-function-using-reflection

 

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

rockage

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值