Golang从数据库查询获取错误值或无法正确存储数据到变量的问题

Golang从数据库查询获取错误值或无法正确存储数据到变量的问题 你好。我刚开始学习Golang,想开发一个类似维基百科的网站。首先,我需要处理数据库来存储和查询子页面,但我一直搞不定,要么从查询中得到错误的值,要么无法正确地将接收到的数据存储到变量中。我的输出看起来像这样:

$ go run main.go
DB connected!
0  []

我的代码:

编译器资源管理器

我检查了相同的查询: image

请看一下我的代码并帮我找出问题。谢谢。


更多关于Golang从数据库查询获取错误值或无法正确存储数据到变量的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

感谢提供这么棒的信息。

更多关于Golang从数据库查询获取错误值或无法正确存储数据到变量的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,我实际上没有看到你的代码。你的链接指向的是 Compiler Explorer。你是想链接一个 GitHub 仓库还是粘贴代码?顺便欢迎来到论坛。

啊,问题出在 Initialize 函数里。具体来说,是你在那个函数中关闭数据库的方式有问题:

func Initialize() error {
	...
	// 一旦初始化完成,我们就关闭了数据库。
	// 因此后续的调用会失败,因为 db 已经关闭了。
	defer Database.Close()
	...
}

你可能希望它在 main 函数退出时才关闭。要做到这一点,你可以在你的 db 包中添加这个:

// 在 db 包中
func Close() {
	Database.Close()
}

…然后在 main 函数中关闭数据库连接:

err := db.Initialize()
if err != nil {
	fmt.Fprintf(os.Stderr, "%v\n", err.Error())
	os.Exit(1)
}
defer db.Close()

你好 Dean! 我的代码应该在这个链接下,但我也会在这里粘贴它:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/rm46627/wiki/db"
)

func main() {

	err := db.Initialize()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err.Error())
		os.Exit(1)
	}

	p, err := db.PageByTitle("test")
    if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err.Error())
		os.Exit(1)
	}
	fmt.Println(p.ID, p.Title, p.Body)
}
package db

import (
	"database/sql"
	"fmt"

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

type Page struct {
	ID    int64
	Title string
	Body  []byte
}

var Database *sql.DB

func Initialize() error {
	var err error
	Database, err = sql.Open("mysql", "root:password@tcp(127.0.0.1:3306)/wiki")
	if err != nil {
		return fmt.Errorf("error during opening database: %v", err)
	}
	defer Database.Close()

	err = Database.Ping()
	if err != nil {
		return fmt.Errorf("error during verifying connection to the database: %v", err)
	}

	fmt.Println("DB connected!")
	return nil
}

func PageByTitle(title string) (*Page, error) {
	var p Page
	row := Database.QueryRow("SELECT * FROM pages WHERE title = ?", title)
	if err := row.Scan(&p.ID, &p.Title, &p.Body); err != nil {
		return &p, fmt.Errorf("page title:%s scan error: %v", title, err)
	}
	return &p, nil
}

从你的代码和输出来看,问题主要出现在数据库查询结果的处理方式上。以下是具体问题和解决方案:

问题分析

  1. Scan方法使用不当:你使用了db.QueryRow().Scan(),但查询返回的是多行结果
  2. 变量声明问题subpages变量声明为切片但未正确初始化
  3. 查询结果处理逻辑错误:单行查询与多行查询混淆

修正后的代码

package main

import (
    "database/sql"
    "fmt"
    "log"
    _ "github.com/go-sql-driver/mysql"
)

type Subpage struct {
    ID   int
    Name string
}

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/wiki")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("DB connected!")

    // 查询所有子页面
    rows, err := db.Query("SELECT id, name FROM subpages")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()

    var subpages []Subpage
    var count int

    for rows.Next() {
        var sp Subpage
        err := rows.Scan(&sp.ID, &sp.Name)
        if err != nil {
            log.Fatal(err)
        }
        subpages = append(subpages, sp)
        count++
    }

    // 检查遍历过程中是否有错误
    if err = rows.Err(); err != nil {
        log.Fatal(err)
    }

    fmt.Printf("%d %v\n", count, subpages)
}

如果只需要查询单行数据:

// 查询单行数据
func getSubpageByID(db *sql.Database, id int) (Subpage, error) {
    var sp Subpage
    err := db.QueryRow("SELECT id, name FROM subpages WHERE id = ?", id).Scan(&sp.ID, &sp.Name)
    if err != nil {
        return sp, err
    }
    return sp, nil
}

使用预编译语句提高性能:

func getAllSubpages(db *sql.DB) ([]Subpage, error) {
    stmt, err := db.Prepare("SELECT id, name FROM subpages")
    if err != nil {
        return nil, err
    }
    defer stmt.Close()

    rows, err := stmt.Query()
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var subpages []Subpage
    for rows.Next() {
        var sp Subpage
        if err := rows.Scan(&sp.ID, &sp.Name); err != nil {
            return nil, err
        }
        subpages = append(subpages, sp)
    }

    return subpages, rows.Err()
}

关键点说明:

  1. 多行查询使用db.Query() + rows.Next()循环
  2. 单行查询使用db.QueryRow().Scan()
  3. 始终检查rows.Err()以确保没有遍历错误
  4. 使用结构体来组织数据更清晰
  5. 及时关闭rowsstmt资源

你的原始代码中使用了QueryRow但期望获取多行结果,这会导致只获取第一行数据。根据你的查询截图显示有3条记录,应该使用多行查询的方式。

回到顶部