简体   繁体   中英

Multiple queries to Postgres within the same function

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)

  1. Does Go properly handle defer rows.Close() in such a case? I mean I have reassignment of rows variable later down the code, so will compiler track both and properly close at the end of a function?

  2. Is it ok to reuse id shared var or should I redeclare it while iterating within rows.Next() loop?

  3. 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.

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.

    1. Regardless of the fact that the rows here has the same reference while being shared between 2 queries (so one rows.Close() call would suffice, unless the library has some special implementation), defining two variables is cleaner, like userRows and bookRows .
    1. 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...)
    1. 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.
    1. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM