go操作DB需要注意的

sgfoot · · 3177 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

# 准备 ``` 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](https://github.com/golang/go/blob/master/src/database/sql/sql.go#L3138) ![](https://upload-images.jianshu.io/upload_images/13827699-036c4ac163427b0d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 一般处理 , 见(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 1. QueryRow 无须关闭 1. 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) } ``` # 总结果 1. Scan 操作时需要使用地址,变量前加& 1. 获取单行数据时会报sql.ErrNoRows错误。Next 1. mysql字段为null时,使用sql.Null*操作 1. Query+Next+Scan需要关闭。QueryRow 自带关闭

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3177 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传