[已解决]Golang向Postgres数据库插入数据时遇到的问题

[已解决]Golang向Postgres数据库插入数据时遇到的问题 大家好, 当我想插入数据库时遇到了一个错误。

我的插入方法:

func RegisterUser(db *sql.DB, w http.ResponseWriter, r *http.Request) {

user := model.User{}

decoder := json.NewDecoder(r.Body)

if err := decoder.Decode(&user); err != nil {

respondError(w, http.StatusBadRequest, err.Error())

return

}

defer r.Body.Close()

sqlStatement := `

INSERT INTO users (id, name, avatar, mobile, birth_day, identify, cart, credit, type, password)

VALUES ($1, $2, $3, $4, $5, &6, &7, &8, &9)

RETURNING id`

stmt, err := db.Prepare(sqlStatement)

fmt.Println("******************here2", user)

if err != nil {

log.Fatal(err)

}

defer stmt.Close()

var userID int

if err := stmt.QueryRow(sqlStatement, user.ID, user.Name, user.Avatar, user.Mobile, user.BirthDay, user.Identify, user.Cart, user.Credit, user.Type, user.Password); err != nil {

//respondError(w, http.StatusInternalServerError, err.Error())

log.Fatal(err)

return

}

fmt.Println("New record ID is:", userID)

respondJSON(w, http.StatusCreated, user)

}

这是错误日志: http: panic serving [::1]:39878: runtime error: invalid memory address or nil pointer dereference goroutine 18 [running]:

更多解释: 我有一个包含以下字段的 User 结构体:

type User struct {
	Base
	Name        string `json:"name"`
	Avatar      string `json:"avatar"`
	Email       string `db:"unique;not null";json:"email"`
	Mobile      string `json:"mobile"`
	BirthDay    string `json:"birthday"`
	Identify    string `json:"identify"`
	Cart        string `json:"cart"`
	Credit      string `json:"credit"`
	Type        int    `json:"type"`
	Password    string `json:"password"`
	Permissions string
}

User 结构体中的 Base 是:

import (

"github.com/jinzhu/gorm"

uuid "github.com/satori/go.uuid"

)

type Base struct {

ID uuid.UUID `db:"type:uuid;primary_key;not null;" json:"-"`

}

func (base *Base) BeforeCreate(scope *gorm.Scope) error {

uuid, err := uuid.NewV4()

if err != nil {

return err

}

return scope.SetColumn("ID", uuid)

}

这个 Base 是为每个 User 记录生成 UUID 的。 但我在这个部分遇到了错误:

    stmt, err := db.Prepare(sqlStatement)

	fmt.Println("******************here2", user)

	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

可以请帮我修复这个部分以将数据插入数据库吗?


更多关于[已解决]Golang向Postgres数据库插入数据时遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

在我的 app.go 文件中,我关闭了数据库连接。这导致了应用程序崩溃。我移除了那行代码,不再关闭连接。现在一切正常了。

func RegisterUser(db *sql.DB, w http.ResponseWriter, r *http.Request) {

	user := model.User{}
	decoder := json.NewDecoder(r.Body)
	if err := decoder.Decode(&user); err != nil {
		respondError(w, http.StatusBadRequest, err.Error())
		return
	}
	defer r.Body.Close()

	stmt, err := db.Prepare("INSERT INTO users(id,name,avatar,mobile, email,birth_day, identify, cart, credit, password, type) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);")

	fmt.Println(db)
	if err != nil {
		fmt.Println("not work")
		panic(err)
	}

	uuid, err := uuid.NewV4()

	res, err := stmt.Exec(uuid, user.Name, user.Avatar, user.Mobile, user.Email, user.BirthDay, user.Identify, user.Cart, user.Credit, user.Password, user.Type)

	fmt.Println(res.LastInsertId())

	//respondJSON(w, http.StatusCreated, user)
}

这是我的用户注册方法,用于将用户插入数据库。希望这对其他人有所帮助。

更多关于[已解决]Golang向Postgres数据库插入数据时遇到的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在我检查时,db 是 nil。在此之前,我使用了 gorm 和一些 Init 方法以及 App 结构体。经过一些更改后,我的代码现在在 app.go 中是这样的:

type App struct {
    Router *mux.Router
    DB     *sql.DB
}

在 Initialize 方法中,我有以下代码:

// App initialize with predefined configuration
func (a *App) Initialize(config *config.Config) {
    dbURI := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s",
        config.DB.Host,
        config.DB.Port,
        config.DB.User,
        config.DB.DbName,
        config.DB.Password)

    db, err := sql.Open(config.DB.Dialect, dbURI)

    if err != nil {
        log.Fatal("Could not connect database")
    }

    defer db.Close()

    err = db.Ping()
    if err != nil {
        panic(err)
    }

    fmt.Println("Successfully connected!")

    //a.DB = model.DBMigrate(db)
    a.Router = mux.NewRouter()
    a.setRouters()
}

如上代码所示,当我使用 gorm 时,a.DB 被赋予了一些值,但现在我刚刚注释掉了这一行。我必须为它设置什么值?因为在我检查时 a.DB 是 nil,我将它传递给 register 方法并收到一个错误。

根据你的代码分析,主要问题出现在以下几个方面:

1. SQL语句占位符数量不匹配

你的SQL语句有10个字段,但只有9个占位符($1到$9)

2. 错误的占位符语法

使用了 &6, &7, &8, &9 而不是 $6, $7, $8, $9, $10

3. UUID处理问题

Base 结构体使用了GORM的钩子,但你的代码使用的是标准库的 database/sql

修复后的代码:

func RegisterUser(db *sql.DB, w http.ResponseWriter, r *http.Request) {
    user := model.User{}
    
    decoder := json.NewDecoder(r.Body)
    if err := decoder.Decode(&user); err != nil {
        respondError(w, http.StatusBadRequest, err.Error())
        return
    }
    defer r.Body.Close()
    
    // 生成UUID(因为不使用GORM的BeforeCreate钩子)
    user.ID = uuid.NewV4()
    
    sqlStatement := `
    INSERT INTO users (id, name, avatar, mobile, birth_day, identify, cart, credit, type, password)
    VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
    RETURNING id`
    
    var userID string
    
    // 直接使用QueryRow,不需要Prepare
    err := db.QueryRow(
        sqlStatement,
        user.ID,      // $1
        user.Name,    // $2
        user.Avatar,  // $3
        user.Mobile,  // $4
        user.BirthDay,// $5
        user.Identify,// $6
        user.Cart,    // $7
        user.Credit,  // $8
        user.Type,    // $9
        user.Password,// $10
    ).Scan(&userID)
    
    if err != nil {
        log.Printf("插入失败: %v", err)
        respondError(w, http.StatusInternalServerError, err.Error())
        return
    }
    
    fmt.Println("New record ID is:", userID)
    respondJSON(w, http.StatusCreated, user)
}

或者使用Prepare的版本:

func RegisterUser(db *sql.DB, w http.ResponseWriter, r *http.Request) {
    user := model.User{}
    
    decoder := json.NewDecoder(r.Body)
    if err := decoder.Decode(&user); err != nil {
        respondError(w, http.StatusBadRequest, err.Error())
        return
    }
    defer r.Body.Close()
    
    // 生成UUID
    user.ID = uuid.NewV4()
    
    sqlStatement := `
    INSERT INTO users (id, name, avatar, mobile, birth_day, identify, cart, credit, type, password)
    VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
    RETURNING id`
    
    stmt, err := db.Prepare(sqlStatement)
    if err != nil {
        log.Printf("准备语句失败: %v", err)
        respondError(w, http.StatusInternalServerError, err.Error())
        return
    }
    defer stmt.Close()
    
    var userID string
    err = stmt.QueryRow(
        user.ID,
        user.Name,
        user.Avatar,
        user.Mobile,
        user.BirthDay,
        user.Identify,
        user.Cart,
        user.Credit,
        user.Type,
        user.Password,
    ).Scan(&userID)
    
    if err != nil {
        log.Printf("插入失败: %v", err)
        respondError(w, http.StatusInternalServerError, err.Error())
        return
    }
    
    fmt.Println("New record ID is:", userID)
    respondJSON(w, http.StatusCreated, user)
}

关键修复点:

  1. 占位符修正$1$10 共10个占位符
  2. UUID生成:手动调用 uuid.NewV4() 生成ID
  3. 错误处理:使用 log.Printf 而不是 log.Fatal,避免服务崩溃
  4. Scan方法:使用 .Scan(&userID) 获取返回的ID

注意:由于你使用了标准库的 database/sql 而不是GORM,BeforeCreate 钩子不会自动执行,需要手动生成UUID。

回到顶部