当使用go-sql-driver时,如何区分连接错误和其他错误?

huangapple go评论85阅读模式
英文:

how can i distinguish connection error with other errors when using go-sql-driver

问题

func mainloop(db *sql.DB) {
type pushTask struct {
TaskId string
Uri string
}

stmt, err := db.Prepare("INSERT INTO ErrPushCache(TaskId, Uri) VALUES(?, ?)")
if err != nil {
    log.Fatal("db.Prepare 失败", err)
}

var (
    mysqlOk bool = true
    task    pushTask
)
for {
    task.TaskId = RandStringRunes(8)
    task.Uri = RandStringRunes(16)

    res, err := stmt.Exec(task.TaskId, task.Uri)
    if err != nil {
        if err == driver.ErrBadConn {
            if mysqlOk {
                log.Print("与 MySQL 的连接似乎断开了,错误信息:", err.Error())
                mysqlOk = false
                os.Exit(1)
            }
        } else {
            log.Print("Exec 失败:", err)
        }

        time.Sleep(2 * time.Second)
        continue
    }
    if !mysqlOk {
        log.Print("与 MySQL 的连接已恢复")
        mysqlOk = true
    }
    lastId, err := res.LastInsertId()
    if err != nil {
        log.Print("LastInsertId 失败:", err)
    }
    rowCnt, err := res.RowsAffected()
    if err != nil {
        log.Print("RowsAffected 失败:", err)
    }
    log.Printf("ID = %d, 受影响的行数 = %d\n", lastId, rowCnt)

    time.Sleep(20 * time.Second)
}

}

func main() {
db, err := sql.Open("mysql",
"rench:ren123@tcp(192.168.1.61:3306)/hunanTV")
if err != nil {
log.Fatal("sql.Open 失败", err)
}

mainloop(db)

defer db.Close()

}

在mainloop函数中,如果MySQL和客户端之间的连接断开,stmt.Exec将失败并返回一个错误。我该如何区分连接错误和其他错误(err == driver.ErrBadConn始终为false)。

如果连接断开,日志将显示:

2016/01/29 17:21:31 Exec 失败 dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:33 Exec 失败 dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:35 Exec 失败 dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:37 Exec 失败 dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:39 Exec 失败 dial tcp 192.168.1.61:3306: getsockopt: connection refused

...

英文:
func mainloop(db *sql.DB) {
    	type pushTask struct {
    		TaskId string
    		Uri    string
    	}
    
    	stmt, err := db.Prepare("INSERT INTO ErrPushCache(TaskId, Uri) VALUES(?, ?)")
    	if err != nil {
    		log.Fatal("db.Prepare Failed ", err)
    	}
    
    	var (
    		mysqlOk bool = true
    		task    pushTask
    	)
    	for {
    		task.TaskId = RandStringRunes(8)
    		task.Uri = RandStringRunes(16)
    
    		res, err := stmt.Exec(task.TaskId, task.Uri)
    		if err != nil {
    			if err == driver.ErrBadConn {
    				if mysqlOk {
    					log.Print("Connection with mysql seems down, %s", err.Error())
    					mysqlOk = false
    					os.Exit(1)
    				}
    			} else {
    				log.Print("Exec failed ", err)
    			}
    
    			time.Sleep(2 * time.Second)
    			continue
    		}
    		if !mysqlOk {
    			log.Print("Connection with mysql is ok now")
    			mysqlOk = true
    		}
    		lastId, err := res.LastInsertId()
    		if err != nil {
    			log.Print("LastInsertId failed ", err)
    		}
    		rowCnt, err := res.RowsAffected()
    		if err != nil {
    			log.Print("RowsAffected failed ", err)
    		}
    		log.Printf("ID = %d, affected = %d\n", lastId, rowCnt)
    
    		time.Sleep(20 * time.Second)
    	}
    }
    
    func main() {
    	db, err := sql.Open("mysql",
    		"rench:ren123@tcp(192.168.1.61:3306)/hunanTV")
    	if err != nil {
    		log.Fatal("sql.Open Failed ", err)
    	}
    
    	mainloop(db)
    
    	defer db.Close()
    }

in the mainloop function, if the connection between mysql and client is broken,stmt.Exec will be failed, it will return a error, how can i distinguish connection error with other errors.(err == driver.ErrBadConn is always false).

if the connection is broken, the log is :

2016/01/29 17:21:31 Exec failed dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:33 Exec failed dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:35 Exec failed dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:37 Exec failed dial tcp 192.168.1.61:3306: getsockopt: connection refused
2016/01/29 17:21:39 Exec failed dial tcp 192.168.1.61:3306: getsockopt: connection refused

...

答案1

得分: 2

网络错误将属于满足net.Error接口的类型。

if err, ok := err.(net.Error); ok {
    log.Println("网络错误:", err)
} else {
    log.Println("其他错误:", err)
}

在大多数情况下,这并不重要,因为操作失败是由于某种原因,你需要处理它。只有当你想根据网络错误采取不同的操作时,你才需要进行检查。

英文:

Network errors will be of a type that satisfies the net.Error interface.

if err, ok := err.(net.Error); ok {
    log.Println("network error:", err)
} else {
    log.Println("other error:", err)
}

In most cases it won't really matter, because the action failed for some reason, and you need to handle it regardless. It's only if you want to take a different action based on a network error that you really need to check.

答案2

得分: 0

这就是 Go 的错误处理方式让我感到困扰的地方。大部分情况下,实际的错误类型没有被记录下来,所以你必须查看源代码并检查代码可能返回的错误。而且在某些情况下,这些错误只是通用的字符串错误,因为代码是特定于平台的,所以错误也是特定于平台的。

你可以通过查看源代码来做到这一点,或者你可以打印错误类型以确切地知道是哪种类型。

log.Printf("%T", err)
英文:

That's where go's error handling is really bothering me. Most of the time actual error types are not documented so you have to go through the source and check which errors the code can return. And in some cases those are just generic string errors because the code is platform specific and, thus, errors are also platform specific.

You can do that, check the source code, or you can print the error type to know exactly which one it is.

log.Printf("%T", err)

huangapple
  • 本文由 发表于 2016年1月29日 17:45:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/35081310.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定