处理Go中的动态错误(特别是database/sql包)

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

Handling Dynamic Errors In Go (Specifically database/sql Package)

问题

在Go语言中使用database/sql包执行sql.Exec等操作时,可能会返回动态生成且未引用的错误,例如:

"Error 1062: Duplicate entry '192' for key 'id'"

问题在于,同一次调用sql.Exec可能还会返回其他错误,例如:

"Error 1146: Table 'tbl' doesn't exist"

在不使用字符串比较或错误代码的模式匹配的情况下,如何区分这两种错误?或者说,这些方法是否是解决这个问题的惯用解决方案?

英文:

Using the database/sql package in go for things like sql.Exec will return dynamically generated, unreferenced errors such as

"Error 1062: Duplicate entry '192' for key 'id'"

The problem is that it can also return errors such as

"Error 1146: Table 'tbl' doesn't exist"

From the same call to sql.Exec

How can I tell the difference between these two errors without

  1. String comparison, or
  2. Pattern matching for error code

Or are those idiomatic viable solutions for this problem?

答案1

得分: 15

database/sql包无法解决这个问题,它是特定于驱动程序的。例如,对于mysql,你可以使用以下代码:

if mysqlError, ok := err.(*mysql.MySQLError); ok {
    if mysqlError.Number == 1146 {
        //处理
    }
}

此外,你还可以找到一些错误常量包,比如来自VividCortex的mysqlerr,并使用它:

if mysqlError, ok := err.(*mysql.MySQLError); ok {
    if mysqlError.Number == mysqlerr.ER_NO_SUCH_TABLE {
        //处理
    }
}

这并不比模式匹配更好,但似乎更符合惯用方式。

英文:

database/sql package does not solve this problem. It's driver specific. For example, for mysql you can use:

if mysqlError, ok := err.(*mysql.MySQLError); ok {
    if mysqlError.Number == 1146 {
        //handling
    }
}

Also, you can find some error constant package, like mysqlerr from VividCortex, and use it:

if mysqlError, ok := err.(*mysql.MySQLError); ok {
	if mysqlError.Number == mysqlerr.ER_NO_SUCH_TABLE {
		//handling
	}
}

It's not much better than pattern matching, but seems to be more idiomatic.

答案2

得分: 0

我认为没有惯用的解决方案,但我编写了一个简单的函数来获取错误编号,这样你就可以轻松地进行比较。

在这个解决方案中,我假设错误消息的构造始终相同:"Error -某个数字-:错误描述"。

如果错误中没有数字或者出现了问题,它会返回0。

func ErrorCode(e error) int {
    err := e.Error() //错误的描述

    if len(err) < 6 { //如果太短,返回0
        return 0
    }
    i := 6 //跳过"Error "部分

    for ; len(err) > i && unicode.IsDigit(rune(err[i])); i++ {
    } //将i递增,直到达到err的末尾或者错误代码的末尾

    n, e := strconv.Atoi(string(err[6:i])) //将其转换为整数
    if e != nil {
        return 0 //出现了问题
    }
    return n //返回错误代码
}

Go playground链接:http://play.golang.org/p/xqhVycsuyI

英文:

I think there's no idiomatic solution, but I wrote a simple function for getting the error number, so you can easily compare them.

In this solution I assume that the construction of the error message is always the same: "Error -some number here-: Error description".

If there's no number in the error or something went wrong it returns 0.

func ErrorCode(e error) int {
	err := e.Error() //the description of the error

	if len(err) &lt; 6 { //if its too small return 0
		return 0
	}
	i := 6 //Skip the part &quot;Error &quot;
	
	for ; len(err) &gt; i &amp;&amp; unicode.IsDigit(rune(err[i])); i++ {
	} // Raising i until we reach the end of err or we reach the end of error code

	n, e := strconv.Atoi(string(err[6:i])) //convert it to int
	if e != nil {
		return 0 //something went wrong
	}
	return n //return the error code
}

Go playground link: http://play.golang.org/p/xqhVycsuyI

huangapple
  • 本文由 发表于 2014年12月25日 11:31:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/27644009.html
匿名

发表评论

匿名网友

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

确定