Golang持久化数据到数据库时遇到可变参数错误

Golang持久化数据到数据库时遇到可变参数错误 在执行如下所示的 INSERT 查询时,我遇到了以下错误。请问解决方案或正确的做法是什么?

谢谢

sql: 转换参数 $1 类型时出错:不支持的类型 interface {},一个接口切片

func main() {
    type dto struct {
        name string
        year uint16
    }

    dto := dto{"abc", 123}

    insert(
        "INSERT INTO `user` (`name`, `found`) VALUES (?, ?)",
        dto.name,
        dto.year,
    )
}

func insert(query string, args ...interface{}) int {
    stmt, err := database.Prepare(query) // database 是 *sql.DB
    if err != nil {
        panic(err)
    }
    defer stmt.Close()

    res, err := stmt.Exec(args)
    if err != nil {
        panic(err) // 此处引发错误
    }

    id, err := res.LastInsertId()
    if err != nil {
        panic(err)
    }

    return id
}

更多关于Golang持久化数据到数据库时遇到可变参数错误的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

除了 stmt.Exec(args...) 之外,似乎还需要进行以下更改。

insert(
        "INSERT INTO `user` (`name`, `found`) VALUES (?, ?)",
        []interface{}{dto.name,
        dto.year}...,
    )

更多关于Golang持久化数据到数据库时遇到可变参数错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


错误原因在于 stmt.Exec(args) 的调用方式。args 已经是 ...interface{} 类型的切片,而 Exec 方法期望接收可变参数,不是单个切片。你需要使用 ... 运算符将切片展开为可变参数。

以下是修正后的代码:

func insert(query string, args ...interface{}) int {
    stmt, err := database.Prepare(query)
    if err != nil {
        panic(err)
    }
    defer stmt.Close()

    // 使用 ... 展开 args 切片
    res, err := stmt.Exec(args...)
    if err != nil {
        panic(err)
    }

    id, err := res.LastInsertId()
    if err != nil {
        panic(err)
    }

    return int(id)
}

关键修改是将 stmt.Exec(args) 改为 stmt.Exec(args...)args... 会将切片中的每个元素作为独立参数传递给 Exec 方法,这与函数签名 Exec(args ...interface{}) 的要求一致。

另外,如果你的数据库是 MySQL,占位符应该是 ? 而不是 $1。你代码中的 SQL 语句使用 ? 占位符是正确的,错误信息中的 $1 可能是其他数据库的占位符格式。确保你的数据库驱动和占位符格式匹配:

// MySQL 使用 ? 占位符
insert(
    "INSERT INTO `user` (`name`, `found`) VALUES (?, ?)",
    dto.name,
    dto.year,
)

如果你的数据库是 PostgreSQL,则需要使用 $1, $2 格式的占位符:

// PostgreSQL 使用 $1, $2 占位符
insert(
    "INSERT INTO user (name, found) VALUES ($1, $2)",
    dto.name,
    dto.year,
)

确保你的数据库驱动支持你使用的占位符语法。

回到顶部