内容简介:初学者使用golang mysql做查询时,一般直接使用原生的select * from table来查询数据:后来数据表结构变动直接导致GetUserInfo()报错了,因为字段对应不上了。然后优化了一版:此时问题解决了,然后继续写类似的代码。
初学者使用golang mysql做查询时,一般直接使用原生的select * from table来查询数据:
type UserInfo struct {
Id int64
Name string
Sex string
//...
}
func GetUserInfo(uid int64) (info UserInfo, err error) {
Db := lib.MysqlConn()
sql := fmt.Sprintf("select * from user where uid=%d", uid)
rows, err := Db.Query(sql)
if err != nil {
return info, err
}
defer Db.Close()
if rows.Next() {
var (
id int64
name string
sex string
//...
)
//得一个个的字段罗列出来
err = rows.Scan(&id, &name, &sex, //...)
info = UserInfo{
Id: id,
Name: name,
Sex: sex,
//...
}
}
return info, nil
}
后来数据表结构变动直接导致GetUserInfo()报错了,因为字段对应不上了。然后优化了一版:
func GetUserInfo(uid int64) (info UserInfo, err error) {
Db := lib.MysqlConn()
sql := fmt.Sprintf("select `id`,`user_name`,`sex`,... from user where uid=%d", uid)
rows, err := Db.Query(sql)
if err != nil {
return
}
defer Db.Close()
if rows.Next() {
//得一个个的字段罗列出来
err = rows.Scan(&info.Id, &info.Name, &info.Sex, //...)
if err != nil {
return
}
}
return
}
此时问题解决了,然后继续写类似的代码。
时间久了,就发现这样写好累,每次都得把所有的字段都罗列出来,而且上下一一对应。
所以就想能不能自动生成上下对应的变量,然后直接用变量来替换上。
如是,就用到了golang的反射,先定义一个结构体和数据表的字段一一对应,并在字段说明里面定义数据库的字段名:
type UserInfo struct {
Id int64 `sql:"id"`
Name string `sql:"user_name"`
Sex string `sql:"sex"`
//...
}
可以使用反射提取出类似`sql:"id"`里面id,然后拼装起来,具体如下
func (ui *UserInfo) allFields() (sqlFields string) {
arr := []string{}
el := reflect.TypeOf(ui).Elem()
for i := 0; i < el.NumField(); i++ {
arr = append(arr, el.Field(i).Tag.Get("sql"))
}
sqlFields = "`" + strings.Join(arr, "`,`") + "`"
return
}
所以上面的函数中 sql 语句的定义就改为了:
//...
sql := fmt.Sprintf("select "+info.allFields()+" from user where uid=%d", uid)
//...
问题又来了,
rows.Scan(&info.Id, &info.Name, &info.Sex, //...)
rows.Scan怎么优化?
这里实际上就是每个字段的地址,如果取出该变量的地址,组成一个切片,然后展开切片就可以了,再来定义方法:
func (ui *UserInfo) allValues() (sqlValues []interface{}) {
vl := reflect.ValueOf(ui).Elem()
num := reflect.TypeOf(ui).Elem().NumField()
for i := 0; i < num; i++ {
sqlValues = append(sqlValues, vl.Field(i).Addr().Interface())
}
return
}
func GetUserInfo(uid int64) (info UserInfo, err error) {
Db := lib.MysqlConn()
sql := fmt.Sprintf("select "+info.allFields()+" from user where uid=%d", uid)
rows, err := Db.Query(sql)
if err != nil {
return
}
defer Db.Close()
if rows.Next() {
//获取每个字段的切片
fields := info.allValues()
err = rows.Scan(fields...)
if err != nil {
return
}
}
return
}
把 info.allFields()和info.allValues()合并在一起返回:
type UserInfo struct {
Id int64 `sql:"id"`
Name string `sql:"user_name"`
Sex string `sql:"sex"`
//...
}
func (ui *UserInfo) allFieldsAndValues() (sqlFields string, sqlValues []interface{}) {
arr := []string{}
el := reflect.TypeOf(ui).Elem()
vl := reflect.ValueOf(ui).Elem()
for i := 0; i < el.NumField(); i++ {
arr = append(arr, el.Field(i).Tag.Get("sql"))
sqlValues = append(sqlValues, vl.Field(i).Addr().Interface())
}
sqlFields = "`" + strings.Join(arr, "`,`") + "`"
return
}
func GetUserInfo(uid int64) (info UserInfo, err error) {
Db := lib.MysqlConn()
sqlFields, sqlValues := info.allFieldsAndValues()
sql := fmt.Sprintf("select "+sqlFields+" from user where uid=%d", uid)
rows, err := Db.Query(sql)
if err != nil {
return
}
defer Db.Close()
if rows.Next() {
err = rows.Scan(sqlValues...)
}
return
}
现在封装起来后就方便多了,不担心数据表结构变动:这里只需要修改结构体UserInfo的信息。
现在又有一个方法需要批量的获取UserInfo,方法UserInfo.allFieldsAndValues()就大有用处了:
func GetAllUserInfo() (all []UserInfo, err error) {
Db := lib.MysqlConn()
info := UserInfo{}
sqlFields, sqlValues := info.allFieldsAndValues()
rows, err := Db.Query("select " + sqlFields + " from user ")
if err != nil {
return
}
defer Db.Close()
for rows.Next() {
err = rows.Scan(sqlValues...)
if err != nil {
return
}
all = append(all, info)
info = UserInfo{}
}
return
}
这里在循环内[for rows.Next(){//...}]因为结构体的传值是值传递,all = append(all, info)操作的是info的一个拷贝。
用完之后在把变量info的值给重置掉:info = UserInfo{}。最后返回all。
Go语言中有的传参是值传递(传值),是一个副本,一个拷贝。
因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;
有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数字时代的营销战略
曹虎、王赛、乔林、【美】艾拉·考夫曼 / 机械工业出版社 / 2017-1 / 99.00元
菲利普•科特勒说,市场比市场营销变得更快(Market changes faster than Marketing),在这个变革的时代,从硅谷、波士顿到北京、上海、深圳,我们正在重新定义公司,重新定义组织,重新定义战略;同样地,营销亦需要重新定义。 从本质上讲,营销战略只有两个时代:实体时代与比特时代,也可称为工业时代与数字时代。从5年前开始,第二个时代正在向未来20年展开画卷,数字创新型企......一起来看看 《数字时代的营销战略》 这本书的介绍吧!