Golang中循环内如何扫描SQL行数据
Golang中循环内如何扫描SQL行数据 大家好 :wave:, 我是Go编程语言的新手,这是我在这个论坛的第一篇帖子,是一个在线课程推荐给我的。2022年还很新鲜,祝大家新年快乐。
我很难理解为什么不能在循环内返回一个sql行?或者我没有理解正确的做法?
我试图在PostgreSQL表中创建一个列,然后返回整个列的行并打印出来。我尝试在循环内完成这个操作(但行不通),而每当我在循环外做这件事时,它就能正常工作。请用你们的智慧启发我 :pray:。
数据库:
go-mvc=# select * from messages;
id | name | message | created_at
-----+-------+-----------------+----------------------------
101 | Ori | Skol! | 2022-01-23 19:43:14.761144
102 | Oin | Raise the axes! | 2022-01-23 19:43:14.763818
103 | Gloin | Bouncing around | 2022-01-23 19:43:14.764389
(3 rows)
控制器:
func CreateMessageProcessJSON(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(405)
return
}
if r.Header.Get("content-type") != "application/json" {
w.WriteHeader(406)
return
}
msgs := []models.MessageJSON{}
helpers.ParseBody(r, &msgs)
// 不工作
// for _, msg := range msgs {
// if err := msg.CreateFromJSON(); err != nil {
// http.Error(w, http.StatusText(500), http.StatusInternalServerError)
// return
// }
// }
// 工作
if err := msgs[0].CreateFromJSON(); err != nil {
http.Error(w, http.StatusText(500), http.StatusInternalServerError)
return
}
pd := models.PageDataJSON{
msgs,
models.RawData{Title: "Show json message"},
}
fmt.Fprintln(w, pd)
}
模型:
type MessageJSON struct {
Id int64 `json:"id"`
Name string `json:"name"`
Message string `json:"msg"`
CreatedAt time.Time `json:"created_at"`
}
func (msg *MessageJSON) CreateFromJSON() (err error) {
// 验证表单值
if msg.Name == "" || msg.Message == "" {
errors.New("this error just triggers another error")
return
}
statement := `INSERT INTO messages (name, message, created_at) VALUES ($1, $2, $3) RETURNING id, name, message, created_at`
stmt, err := db.Db.Prepare(statement)
if err != nil {
return
}
// 使用 QueryRow 返回一行并将返回的 id 扫描到 User 结构体中
err = stmt.QueryRow(msg.Name, msg.Message, time.Now()).Scan(&msg.Id, &msg.Name, &msg.Message, &msg.CreatedAt)
return
}
每次我发出POST请求时,列都会被创建,但 scan 似乎对我的结构体没有任何影响。
带循环的POST请求:
% curl -X POST \
http://localhost:8080/messages/createjson/process \
-H "Content-Type: application/json" \
-d '[{"name":"Ori", "msg":"Skol!"},{"name":"Oin","msg":"Raise the axes!"},{"name":"Gloin","msg":"Bouncing around"}]' -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1:8080...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /messages/createjson/process HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.77.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 111
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sun, 23 Jan 2022 18:43:14 GMT
< Content-Length: 178
< Content-Type: text/plain; charset=utf-8
<
{[{0 Ori Skol! 0001-01-01 00:00:00 +0000 UTC} {0 Oin Raise the axes! 0001-01-01 00:00:00 +0000 UTC} {0 Gloin Bouncing around 0001-01-01 00:00:00 +0000 UTC}] {Show json message}}
* Connection #0 to host localhost left intact
不带循环的POST请求(会给我正确的ID,但这不是我想要的):
% curl -X POST \
http://localhost:8080/messages/createjson/process \
-H "Content-Type: application/json" \
-d '[{"name":"ID?", "msg":"CHEERS!!!"}]' -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1:8080...
* connect to ::1 port 8080 failed: Connection refused
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /messages/createjson/process HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.77.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 35
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sun, 23 Jan 2022 18:52:18 GMT
< Content-Length: 83
< Content-Type: text/plain; charset=utf-8
<
{[{105 ID? CHEERS!!! 2022-01-23 19:52:18.941026 +0000 +0000}] {Show json message}}
* Connection #0 to host localhost left intact
保重。
更多关于Golang中循环内如何扫描SQL行数据的实战教程也可以访问 https://www.itying.com/category-94-b0.html
4 回复
非常感谢 @christophberger,这不仅解决了我的问题,还让我豁然开朗! 🎉
问题在于你的 CreateFromJSON() 方法使用了指针接收器,但在循环中传递的是切片的副本。当你在循环中迭代 msgs 时,每个 msg 都是切片元素的副本,而不是原始元素的引用。
以下是修复后的代码:
func CreateMessageProcessJSON(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(405)
return
}
if r.Header.Get("content-type") != "application/json" {
w.WriteHeader(406)
return
}
msgs := []models.MessageJSON{}
helpers.ParseBody(r, &msgs)
// 修复:使用索引访问原始切片元素
for i := range msgs {
if err := msgs[i].CreateFromJSON(); err != nil {
http.Error(w, http.StatusText(500), http.StatusInternalServerError)
return
}
}
pd := models.PageDataJSON{
msgs,
models.RawData{Title: "Show json message"},
}
fmt.Fprintln(w, pd)
}
或者,如果你需要修改结构体字段,可以使用指针切片:
func CreateMessageProcessJSON(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(405)
return
}
if r.Header.Get("content-type") != "application/json" {
w.WriteHeader(406)
return
}
msgs := []*models.MessageJSON{}
helpers.ParseBody(r, &msgs)
// 现在可以使用范围循环,因为每个元素都是指针
for _, msg := range msgs {
if err := msg.CreateFromJSON(); err != nil {
http.Error(w, http.StatusText(500), http.StatusInternalServerError)
return
}
}
pd := models.PageDataJSON{
msgs,
models.RawData{Title: "Show json message"},
}
fmt.Fprintln(w, pd)
}
同时需要更新 PageDataJSON 结构体以支持指针切片:
type PageDataJSON struct {
Messages []*MessageJSON `json:"messages"`
RawData RawData `json:"raw_data"`
}
这样修改后,Scan() 方法就能正确更新结构体字段了。


