go数据库查询 scan error sql: Scan error on column index XXXXX unsupported Scan, storing driver.Value ...
使用go查询数据库时,有时候会遇到 scan error sql: Scan error on column index XXXXX unsupported Scan, storing driver.Value type <nil>这个错误
这个错误产生的原因是,查询的结果中有的值是NULL , 导致在读查询结果时,遇到NUL 类型的数值,无法正确读出数值
现在通过一个简单的例子复现一下
先创建一个简单的表
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
其中 name
这个字段默认是NULL
的,现在插入几条数据
insert into user(`id`,`name`) values(1,'A');
insert into user(`id`,`name`) values(2,'B');
insert into user(`id`,`name`) values(3,NULL);
go代码
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
type User struct {
id uint32
name string
}
func main() {
db := Conn()
if db == nil {
return
}
result := make([]*User, 0, 10)
q := "SELECT `id`, `name` FROM `user`"
if rows, err := db.Query(q); err == nil {
for rows.Next() {
id := uint32(0)
name := ""
if err := rows.Scan(&id, &name); err == nil {
result = append(result, &User{
id: id,
name: name,
})
} else {
fmt.Println("rows scan error", err)
}
}
} else {
fmt.Println("query error", err)
}
for _, v := range result {
fmt.Println(v)
}
}
func Conn() *sql.DB {
db, err := sql.Open("mysql", "root:root123456!@tcp(39.96.173.215)/go_test")
if err != nil {
fmt.Print("sql open error", err)
return nil
}
err2 := db.Ping()
if err2 != nil {
fmt.Print("sql pin error", err2)
return nil
}
return db
}
运行后,报错,这个错误有两种解决办法
- 从数据层面解决,把
name
字段设置为非空字段,并且默认值设置为""空字符串,问题就解决了
改一下表
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
查询结果是正常的
对于一些特殊的查询,结果中难免会有NULL值,比如连接查询等等,这时候需要用第二种方式来解决
- 使用go 提供的
sql.NullString
类型值来结局,这个是string
类型的, go 还提供了其他类型的,还有NullBool
bool类型的,NullFloat64
float64类型的,NullInt64
int64类型的
为了方便,还是把表改回最开始,name
默认是NULL类型的
修改一下代码
result := make([]*User, 0, 10)
q := "SELECT `id`, `name` FROM `user`"
if rows, err := db.Query(q); err == nil {
for rows.Next() {
id := uint32(0)
var name sql.NullString
if err := rows.Scan(&id, &name); err == nil {
u := &User{
id: id,
}
if name.Valid {
u.name = name.String
} else {
u.name = ""
}
result = append(result, u)
} else {
fmt.Println("rows scan error", err)
}
}
} else {
fmt.Println("query error", err)
}
把 name 的类型改为 sql.NullString
并且在查询完成后,判断一下name是否有效
看一下结果没有问题
到这问题解决了