database/sql

在一些地方,错误行为是特殊情况,或者您可能需要了解一些额外信息。

来自迭代结果集产生的错误

考虑以下代码:

for rows.Next() {
    // ...
}
if err = rows.Err(); err!= nil {
    // 在这里处理错误
}
rows.Err()rows.Next()rows.Close()
来自关闭结果集产生的错误
sql.Rows
for rows.Next() {
    // ...
     break;  // 糟糕,行未关闭!内存泄漏...
}
// 执行通常的 "if err = rows.Err()" [此处省略] ...
// 在这里 [re?] 关闭总是安全的:
if err = rows.Close(); err != nil {
    // 但是如果出现错误该怎么办?
    log.Println(err)
}
rows.Close()rows.Close()
来自 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)
id = 1.Scan()name
sql.ErrNoRowsQueryRow()
Scan()
var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
    if err == sql.ErrNoRows {
        //没有行,但也没有错误发生
    } else {
        log.Fatal(err)
    }
}
fmt.Println(name)
QueryRow()QueryRow()Scan()
QueryRow()
识别特定的数据库错误

编写如下代码可能很有诱惑力:

rows, err := db.Query("SELECT someval FROM sometable")
// 错误包含:
// ERROR 1045 (28000):Access denied for user 'foo'@'::1' (using password: NO)
if strings.Contains(err.Error(), "Access denied")  {
    // 处理被拒绝的错误
}

然而,这并不是最好的方法。例如,字符串值可能会有所不同,具体取决于服务器使用哪种语言发送错误消息。最好通过比较错误编号来确定具体的错误是什么。

database/sql
if driverErr, ok := err.(*mysql.MySQLError); ok { // 现在可以直接访问错误编号
    if driverErr.Number == 1045 {
        // 处理被拒绝的错误
    }
}
MySQLError.Number
pq
if driverErr, ok := err.(*mysql.MySQLError); ok  {
    if driverErr.Number == mysqlerr.ER_ACCESS_DENIED_ERROR {
        // 处理被拒绝的错误
    }
}
处理连接错误

如果您与数据库的连接被删除、终止或出现错误怎么办?

database/sql
kill