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