Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feedback] Use select query into struct occour 'name "title": destination not a pointer' error #18

Closed
Kabochar opened this issue Jan 13, 2024 · 8 comments

Comments

@Kabochar
Copy link

Kabochar commented Jan 13, 2024

Hi, @lesismal 老大

在使用 query to struct 的时候,要求 struct 必须定义完整的字段,否则会提示以下错误

sql: Scan error on column index 1, name "title": destination not a pointer

但在使用 query to struct slice 的时候,则能完整输出结果

是否开发者在使用 sqlw query to struct 时候需要明确数据库的各个字段?

Example Code

package main

import (
	"errors"
	"log"

	_ "github.com/go-sql-driver/mysql"
	"github.com/lesismal/sqlw"
)

// init table 建表语句
// CREATE TABLE `t_test`  (
// `id` bigint(20) NOT NULL AUTO_INCREMENT,
// `title` varchar(300) NOT NULL,
// PRIMARY KEY (`id`) USING BTREE
// ) ENGINE = InnoDB;

type Model struct {
	Id int64 `db:"id"`
	// Title string `db:"title" json:"title,omitempty"` // 标题
}

func main() {
	db, err := sqlw.Open("mysql", "sql_dsn", "db")
	if err != nil {
		log.Panic(err)
	}
	var result sqlw.Result

	var model Model
	result, err = db.Select(&model, "select * from t_test")
	if err != nil && !errors.Is(err, sqlw.ErrNotFound) {
		log.Panic(err)
	}
	log.Println("model:", model)
	log.Println("sql:", result.Sql())

	log.Println("____________________________________________")

	var models []*Model // type []Model is also fine
	result, err = db.Select(&models, "select * from t_test limit 1")
	if err != nil && !errors.Is(err, sqlw.ErrNotFound) {
		log.Panic(err)
	}
	for i, v := range models {
		log.Printf("models[%v]: %v", i, v)
	}
	log.Println("sql:", result.Sql())
}

Output print ( remove panic log)

2024/01/13 14:28:07 sql: Scan error on column index 1, name "title": destination not a pointer
2024/01/13 14:28:07 model: {1}
2024/01/13 14:28:07 sql: "select * from t_test", []
2024/01/13 14:28:07 ____________________________________________
2024/01/13 14:28:07 models[0]: &{1}
2024/01/13 14:28:07 sql: "select * from t_test limit 1", []
@lesismal
Copy link
Owner

lesismal commented Jan 13, 2024

感谢关注使用和反馈!

是否开发者在使用 sqlw query to struct 时候需要明确数据库的各个字段?

mysql的查询本来就是需要明确database name的,分几种情况:

  1. sql初始化的时候可以带上你想要连接到的database,这样连上之后默认的就是这个database、后续执行该database的语句就不需要指定database name
  2. 连接上之后,Exec("use database_name") 切换当前默认的database,后续执行该database的语句就不需要指定database name。但这样好像只是当前执行的这个连接生效,并发产生新连接的时候仍然需要让新的连接生效、但用户自己不方便知道是不是新连接,所以如果是事务,用tx可以这样用,因为每次tx在commit或者rollback前会独占这个连接
  3. 每次语句都带上database name,例如我例子里那种、或者每次语句先use database(如果是单次Exec里包含多条语句,需要在初始化的sql string上带上multiStatements=true、否则单次Exec没法执行多条sql语句)。sqlw例子中因为是从头创建database、table,刚开始连上来的时候还不存在database、所以sql初始化连接的string里没法指定database,所以为了省事,就每个语句都带上database name了

我个人比较喜欢每次语句带上database name(database_name.table_name):

  1. 方便不同项目降成本合并使用相同物理数据库的时候迁移;
  2. 多租户系统的database级隔离也比较方便,前阵子有在v站上看到有人问这个多租户的问题就是类似的情况,多租户共用相同物理库,如果创建多个db实例、每个都是自己的连接池,连接总数量可能会高、不好控制。每次指定指定database、单个服务节点可以共用一个db实例、共用一组连接池,避免单个服务到数据库连接池数量过多、整个集群到数据库连接数爆炸导致mysql server压力大

@lesismal
Copy link
Owner

在使用 query to struct 的时候,要求 struct 必须定义完整的字段,否则会提示以下错误

前面的错误,可能是由于你的语句里没有明确database name所以查询到的结果赋值失败,先试试明确database后正确写法是否有问题吧

@lesismal
Copy link
Owner

前面的错误,可能是由于你的语句里没有明确database name所以查询到的结果赋值失败,先试试明确database后正确写法是否有问题吧

哦这个我前面理解错了,你的意思是说,sql查询所有字段出来、例如10个字段,结构体字段少于10个所以失败是吧?
这个我先看下

@Kabochar
Copy link
Author

是的。数据库定义 10 个字段,但是结构体查询仅定义 1个,从而出现上述的错误

@Kabochar
Copy link
Author

Kabochar commented Jan 13, 2024

debug 过大概在这个部分,query 的时候 row 传递的参数非 struct 定义的数量?

image

select 指定 field 时候倒是能避免出现上述的错误

sql: Scan error on column index 1, name "title": destination not a pointer

@lesismal
Copy link
Owner

对的,就是这里这个bug

看了下数组接收器的时候是没这个bug的,struct漏掉了:
https://github.com/lesismal/sqlw/blob/master/convert.go#L198

struct没有对应字段的时候缺少了有效的receiver,刚提交到了这个分支,试下吧:
https://github.com/lesismal/sqlw/tree/nil_receiver_fields

go get -u github.com/lesismal/sqlw@nil_receiver_fields

@Kabochar
Copy link
Author

可以的,能正常工作了。谢谢 fix 👍

@lesismal
Copy link
Owner

好的,感谢反馈 👍

发布了 v1.1.0 ,可以用它了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants