Go的database/sql的rows.Scan如何使用

Rif*_*ife 9 go

我使用 database/sql 并定义了一个到 DB 表列(标签字段)的结构映射:

// Users ...
type Users struct {
    ID            int64  `field:"id"`                      
    Username      string `field:"username"`           
    Password      string `field:"password"`           
    Tel           string `field:"tel"`                   
}
Run Code Online (Sandbox Code Playgroud)

然后我查询:

        rows, err := db.Query(sql)  // select * from users
        if err != nil {
            fmt.Println(err)
        }
        defer rows.Close()
        for rows.Next() {
            user := new(Users)

            // works but I don't think it is good code for too many columns
            err = rows.Scan(&user.ID, &user.Username, &user.Password, &user.Tel)

            // TODO: How to scan in a simple way 


            if err != nil {
                fmt.Println(err)
            }
            fmt.Println("user: ", user)
            list = append(list, *user)
        }
        if err := rows.Err(); err != nil {
            fmt.Println(err)
        }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的rows.Scan(),我必须编写所有列,而且我认为这不是 20 列或更多列的好方法。

如何以清晰的方式扫描。

Rif*_*ife 13

使用反射是一个很好的做法:

    for rows.Next() {
        user := Users{}

        s := reflect.ValueOf(&user).Elem()
        numCols := s.NumField()
        columns := make([]interface{}, numCols)
        for i := 0; i < numCols; i++ {
            field := s.Field(i)
            columns[i] = field.Addr().Interface()
        }

        err := rows.Scan(columns...)
        if err != nil {
            log.Fatal(err)
        }
        log.Println(user)
    }
Run Code Online (Sandbox Code Playgroud)


ale*_*ulf 5

您可以考虑使用 jmoiron 的sqlx包。它支持分配给结构。

摘自自述文件:

type Place struct {
    Country string
    City    sql.NullString
    TelCode int
}
 places := []Place{}
 err = db.Select(&places, "SELECT * FROM place ORDER BY telcode ASC")
 if err != nil {
     fmt.Println(err)
      return
 }
Run Code Online (Sandbox Code Playgroud)