准备
CREATE TABLE `nation` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(25) DEFAULT '' COMMENT '国家名称',
`age` int(11) unsigned DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `nation` VALUES ('1', '', '3');
INSERT INTO `nation` VALUES ('2', '2', null);
连接库的操作
func main() {
db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
if err != nil {
log.Fatal(err)
}
defer db.Close()
Find(db)
First(db)
}
处理sql.ErrNoRows错误
只有获取单行数据时,Scan没有匹配到结果集则会报sql.ErrNoRows错误。
https://github.com/golang/go/blob/master/src/database/sql/sql.go#L3138
一般处理 , 见(1)处
func First(db *sql.DB) {
sqlText := "select `id`, `age` from nation where id = ?"
stmt, err := db.Prepare(sqlText)
if err != nil {
log.Fatal(err)
}
var (
id int32
age int32
)
err = stmt.QueryRow(1).Scan(&id, &age)
if err != nil && err != sql.ErrNoRows { // (1)过滤空的情况
log.Fatal(err)
}
fmt.Printf("ID:%d, value:%d\n", id, age)
}
mysql 字段为null如何处理
如nation表里的age字段, DEFAULT NULL。 (2)处报错
func First(db *sql.DB) {
sqlText := "select `id`, `age` from nation where id = ?"
stmt, err := db.Prepare(sqlText)
if err != nil {
log.Fatal(err)
}
var (
id int32
age int32
)
err = stmt.QueryRow(2).Scan(&id, &age) //(2)age 处报错
if err != nil && err != sql.ErrNoRows {
log.Fatal(err)
}
fmt.Printf("ID:%d, value:%d\n", id, age)
}
直接报错:字段age为null, 不支持操作,因为age是整型。
2020/04/03 19:03:55 sql: Scan error on column index 1, name "age": converting NULL to int32 is unsupported
解决方法
见(3), (4)处解决
func First(db *sql.DB) {
sqlText := "select `id`, `age` from nation where id = ?"
stmt, err := db.Prepare(sqlText)
if err != nil {
log.Fatal(err)
}
var (
id int32
age sql.NullInt32 // (3) 修改前 int32
)
err = stmt.QueryRow(2).Scan(&id, &age)
if err != nil && err != sql.ErrNoRows {
log.Fatal(err)
}
fmt.Printf("ID:%d, value:%d\n", id, age.Int32) // (4) 修改前age
}
destination not a pointer 目标不是指针
func First(db *sql.DB) {
sqlText := "select `id`, `age` from nation where id = ?"
stmt, err := db.Prepare(sqlText)
if err != nil {
log.Fatal(err)
}
var (
id int32
age sql.NullInt32
)
err = stmt.QueryRow(2).Scan(&id, age) // (4) Scan要使用地址赋值,所以报错。
if err != nil && err != sql.ErrNoRows {
log.Fatal(err)
}
fmt.Printf("ID:%d, value:%d\n", id, age.Int32)
}
报错:
2020/04/03 19:10:26 sql: Scan error on column index 1, name "age": destination not a pointer
解决方法:变量前加&
err = stmt.QueryRow(2).Scan(&id, &age)
关闭 rows
- QueryRow 无须关闭
- Query+Next+Scan需要关闭。
func Find(db *sql.DB) {
sqlText := "select `id`, `age` from nation where id = ?"
stmt, err := db.Prepare(sqlText)
if err != nil {
log.Fatal(err)
}
rows, err := stmt.Query(21)
if err != nil {
log.Fatal(err)
}
defer rows.Close() // 关闭,防止进一步的枚举
var (
id int
value int
)
list := make(map[int]int)
for rows.Next() {
err = rows.Scan(&id, &value)
if err != nil {
log.Fatal(err)
}
list[id] = cast.ToInt(value)
}
fmt.Println(list)
}
总结果
- Scan 操作时需要使用地址,变量前加&
- 获取单行数据时会报sql.ErrNoRows错误。Next
- mysql字段为null时,使用sql.Null*操作
- Query+Next+Scan需要关闭。QueryRow 自带关闭
有疑问加站长微信联系(非本文作者)