如何解决Go中sql: converting argument $1 type不支持[]interface{}的错误
Go语言数据库Delete函数错误解决
错误原因分析
- 遍历取值错误:你用
for id := range ids遍历切片时,id是切片的索引(int类型),而非实际的int64类型ID值,导致ids_interface里存的不是要删除的目标ID。 - SQL构造与参数传递错误:
- 直接拼接ID字符串到SQL语句存在SQL注入风险,且不符合参数化查询的规范。
stmt.ExecContext(ctx, ids_interface)直接传递切片,而ExecContext需要的是可变参数,需用...展开切片;同时原SQL的占位符数量和参数数量完全不匹配。
修正后的代码
1. 移除不安全的String拼接函数
不需要手动拼接ID字符串,改用参数化的占位符构造IN子句,从根源避免SQL注入。
2. 修正DeleteTODO函数
// DeleteTODO deletes TODOs on DB by ids. func (s *TODOService) DeleteTODO(ctx context.Context, ids []int64) error { // 构造IN子句的占位符:ids有n个元素就生成n个?,用逗号分隔 placeholders := make([]string, len(ids)) for i := range placeholders { placeholders[i] = "?" } deleteSQL := fmt.Sprintf(`DELETE FROM todos WHERE id IN (%s)`, strings.Join(placeholders, ",")) // 正确转换ids为[]interface{}:遍历取值而非索引 idsInterface := make([]interface{}, len(ids)) for i, id := range ids { idsInterface[i] = id } stmt, err := s.db.PrepareContext(ctx, deleteSQL) if err != nil { log.Fatal("server/todo.go delete prepareContext ", err) } defer stmt.Close() // 用...展开切片传递参数,匹配SQL中的占位符数量 res, err := stmt.ExecContext(ctx, idsInterface...) if err != nil { return err } rows, err := res.RowsAffected() if err != nil { log.Fatal("server/todo.go stmt.RowsAffected()", err) } // 批量删除场景下,rows可能大于1,调整判断逻辑为检查是否有数据被删除 if rows == 0 { err := model.ErrNotFound{ErrorWhen: time.Now(), ErrorWhat: "no TODOs found to delete"} return &err } return nil }
关键修正点说明
- 安全构造SQL:通过生成对应数量的
?占位符,避免直接拼接字符串,彻底杜绝SQL注入风险。 - 正确遍历切片:使用
for i, id := range ids获取实际的ID值,转换为interface{}类型存入切片,保证参数值正确。 - 参数传递方式:调用
ExecContext时用idsInterface...将切片展开为可变参数,匹配SQL中的占位符数量,解决类型不匹配的错误。 - 合理的行数判断:原代码中
rows !=1的逻辑不适用于批量删除场景,改为判断rows ==0来处理未找到待删除数据的情况。
内容的提问来源于stack exchange,提问作者user20380228
相关产品推荐
相关产品推荐

