首先我们看下官方 Go 语言操作 DB 的示例:
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package sql_test
- import (
- "database/sql"
- "fmt"
- "log"
- )
- var db *sql.DB
- func ExampleDB_Query() {
- age := 27
- rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
- if err != nil {
- log.Fatal(err)
- }
- defer rows.Close()
- for rows.Next() {
- var name string
- if err := rows.Scan(&name); err != nil {
- log.Fatal(err)
- }
- fmt.Printf("%s is %d\n", name, age)
- }
- if err := rows.Err(); err != nil {
- log.Fatal(err)
- }
- }
- func ExampleDB_QueryRow() {
- id := 123
- var username string
- err := db.QueryRow("SELECT username FROM users WHERE id=?", id).Scan(&username)
- switch {
- case err == sql.ErrNoRows:
- log.Printf("No user with that ID.")
- case err != nil:
- log.Fatal(err)
- default:
- fmt.Printf("Username is %s\n", username)
- }
- }
- func ExampleDB_Query_multipleResultSets() {
- age := 27
- q := `
- create temp table uid (id bigint); -- Create temp table for queries.
- insert into uid
- select id from users where age < ?; -- Populate temp table.
- -- First result set.
- select
- users.id, name
- from
- users
- join uid on users.id = uid.id
- ;
- -- Second result set.
- select
- ur.user, ur.role
- from
- user_roles as ur
- join uid on uid.id = ur.user
- ;
- `
- rows, err := db.Query(q, age)
- if err != nil {
- log.Fatal(err)
- }
- defer rows.Close()
- for rows.Next() {
- var (
- id int64
- name string
- )
- if err := rows.Scan(&id, &name); err != nil {
- log.Fatal(err)
- }
- fmt.Printf("id %d name is %s\n", id, name)
- }
- if !rows.NextResultSet() {
- log.Fatal("expected more result sets", rows.Err())
- }
- var roleMap = map[int64]string{
- 1: "user",
- 2: "admin",
- 3: "gopher",
- }
- for rows.Next() {
- var (
- id int64
- role int64
- )
- if err := rows.Scan(&id, &role); err != nil {
- log.Fatal(err)
- }
- fmt.Printf("id %d has role %s\n", id, roleMap[role])
- }
- if err := rows.Err(); err != nil {
- log.Fatal(err)
- }
- }
我们需要了解的几种错误处理的场景:
- Errors From Iterating Resultsets:
- for rows.Next() {
- // ...
- }
- if err = rows.Err(); err != nil {
- // handle the error here
- }
- Errors From Closing Resultsets:
- for rows.Next() {
- // ...
- break; // whoops, rows is not closed! memory leak...
- }
- // do the usual "if err = rows.Err()" [omitted here]...
- // it's always safe to [re?]close here:
- if err = rows.Close();
- err != nil {
- // but what should we do if there's an error?
- log.Println(err)
- }
- Errors From QueryRow():
- var name string
- err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
- if err != nil {
- log.Fatal(err)
- }
- fmt.Println(name)
上面的查询 name 很有可能没有值所以, 最好使用下面的方式进行错误处理:
- var name string
- err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
- if err != nil {
- if err == sql.ErrNoRows {
- // there were no rows, but otherwise no error occurred
- } else {
- log.Fatal(err)
- }
- }
- fmt.Println(name)
- Identifying Specific Database Errors:
- rows, err := db.Query("SELECT someval FROM sometable")
- // err contains:
- // ERROR 1045 (28000): Access denied for user 'foo'@'::1' (using password: NO)
- if strings.Contains(err.Error(), "Access denied") {
- // Handle the permission-denied error
- }
然而上面的处理并不是 database/sql 方式, 我们应该用下面的方式处理:
- if driverErr, ok := err.(*mysql.MySQLError); ok { // Now the error number is accessible directly
- if driverErr.Number == 1045 {
- // Handle the permission-denied error
- }
- }
然而上面方式看起来依然很不清真, 我们可以
- if driverErr, ok := err.(*mysql.MySQLError); ok {
- if driverErr.Number == mysqlerr.ER_ACCESS_DENIED_ERROR {
- // Handle the permission-denied error
- }
- }
来源: https://juejin.im/entry/5aa60100518825558453a2e0