英文:
Multiple queries to Postgres within the same function
问题
我是Go的新手,所以提前对愚蠢的问题表示抱歉!
我正在使用Gin框架,并且想在同一个处理程序中对数据库进行多个查询(使用database/sql
+ lib/pq
)。
userIds := []int{}
bookIds := []int{}
var id int
/* 在此处理第一个查询 */
rows, err := pgClient.Query(getUserIdsQuery)
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
err := rows.Scan(&id)
if err != nil {
return
}
userIds = append(userIds, id)
}
/* 在此处理第二个查询 */
rows, err = pgClient.Query(getBookIdsQuery)
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
err := rows.Scan(&id)
if err != nil {
return
}
bookIds = append(bookIds, id)
}
对于这段代码,我有几个问题(欢迎任何改进和最佳实践):
1)在这种情况下,Go是否正确处理defer rows.Close()
?我的意思是,我在代码后面重新分配了rows
变量,所以编译器会跟踪两者并在函数末尾正确关闭吗?
2)在rows.Next()
循环中,重复使用id
共享变量是否可以?还是应该在迭代时重新声明它?
3)在一个处理程序中有更多查询的更好方法是什么?我应该使用某种接受查询和切片并填充检索到的id的Writer
吗?
谢谢。
英文:
I'm new to Go, so sorry for the silly question in advance!
I'm using Gin framework and want to make multiple queries to the database within the same handler (database/sql
+ lib/pq
)
userIds := []int{}
bookIds := []int{}
var id int
/* Handling first query here */
rows, err := pgClient.Query(getUserIdsQuery)
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
err := rows.Scan(&id)
if err != nil {
return
}
userIds = append(userIds, id)
}
/* Handling second query here */
rows, err = pgClient.Query(getBookIdsQuery)
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
err := rows.Scan(&id)
if err != nil {
return
}
bookIds = append(bookIds, id)
}
I have a couple of questions regarding this code (any improvements and best practices would be appreciated)
-
Does Go properly handle
defer rows.Close()
in such a case? I mean I have reassignment ofrows
variable later down the code, so will compiler track both and properly close at the end of a function? -
Is it ok to reuse
id
shared var or should I redeclare it while iterating withinrows.Next()
loop? -
What's the better approach of having even more queries within one handler? Should I have some kind of
Writer
that accepts query and slice and populate it with ids retrieved?
Thanks.
答案1
得分: 1
我从未使用过go-pg
库,我的回答主要集中在其他方面,这些内容是通用的,与golang或go-pg无关。
-
- 不管
rows
在这里是否具有相同的引用,在两个查询之间共享(因此只需要一个rows.Close()
调用,除非库有一些特殊的实现),定义两个变量更清晰,比如userRows
和bookRows
。
- 不管
-
- 尽管我已经说过我没有使用过
go-pg
,但我相信你不需要手动迭代行并手动扫描所有行的id,我相信该库已经提供了一些类似的API(根据快速查看文档):
userIds := []int{} err := pgClient.Query(&userIds, "select id from users where ...", args...)
- 尽管我已经说过我没有使用过
-
- 关于你的第二个问题,这取决于你对“ok”的理解。由于你正在进行一些同步迭代,我认为不会导致错误,但从编码风格的角度来看,我个人不会这样做。
-
- 我认为在你的情况下,最好的做法是这样的:
// repo层 func getUserIds(args whatever) ([]int, error) {...} // 根据你的打包逻辑,这些可以暴露出去 func getBookIds(args whatever) ([]int, error) {...} // service层,或者你想要聚合两个查询的任何地方 func getUserAndBookIds() ([]int, []int, error) { userIds, err := getUserIds(...) // 潜在的错误处理 bookIds, err := getBookIds(...) // 潜在的错误处理 return userIds, bookIds, nil // 之前已经处理了错误 }
我认为这段代码更易于阅读和维护。你不会遇到变量重新赋值和其他问题。
你可以查看go-pg文档以获取有关如何改进查询的更多详细信息。
英文:
I've never worked with go-pg
library, and my answer is mostly focused on the other stuff, which are generic, and are not specific to golang or go-pg.
-
- Regardless of the fact that the
rows
here has the same reference while being shared between 2 queries (so onerows.Close()
call would suffice, unless the library has some special implementation), defining two variables is cleaner, likeuserRows
andbookRows
.
- Regardless of the fact that the
-
- Although I already said that I have not worked with
go-pg
, I believe that you wont need to iterate through rows and scan the id for all the rows manually, I believe that the lib has provided some API like this (based on the quick look on the documentations):
userIds := []int{} err := pgClient.Query(&userIds, "select id from users where ...", args...)
- Although I already said that I have not worked with
-
- Regarding your second question, it depends on what you mean by "ok". Since your doing some synchronous iteration, I don't think it would result into bugs, but when it comes to coding style, personally, I wouldn't do this.
-
- I think that the best thing to do in your case is this:
// repo layer func getUserIds(args whatever) ([]int, err) {...} // these can be exposed, based on your packaging logic func getBookIds(args whatever) ([]int, err) {...} // service layer, or wherever you want to aggregate both queries func getUserAndBookIds() ([]int, []int, err) { userIds, err := getUserIds(...) // potential error handling bookIds, err := getBookIds(...) // potential error handling return userIds, bookIds, nil // you have done err handling earlier }
I think this code is easier to read/maintain. You won't face the variable reassignment and other issues.
You can take a look at the go-pg documentations for more details on how to improve your query.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论