0

我有一个旨在处理 TSQL 查询的函数。本质上,它尝试创建到服务器的连接、运行查询、提交然后关闭连接。目前,我们依赖于mssqldb 驱动程序,因为后端是 Azure SQL。

func (requester *Requester) doTransaction(ctx context.Context, isolation sql.IsolationLevel, 
    txFunc func(*sql.Tx) error) error {

    // First, attempt to get a connection from the connection pool. If this fails return an error
    conn, err := requester.conn.Conn(ctx)
    if err != nil {
        fmt.Printf("Conn failed, Error type: %s\n", reflect.TypeOf(err))
        log.Printf("Conn failed, error: %v", err)
        return err
    }

    // Before we continue on, ensure that the connection is clsoed and returned to the connection pool
    defer func() {
        if err := conn.Close(); err != nil {
            log.Printf("Close failed, error: %v", err)
        }
    }()

    // Next, start the transaction with the given context and the default isolation
    tx, err := conn.BeginTx(ctx, &sql.TxOptions{Isolation: isolation, ReadOnly: false})
    if err != nil {
        fmt.Printf("BeginTx failed, Error type: %s\n", reflect.TypeOf(err))
        log.Printf("BeginTx failed, error: %v", err)
        return err
    }

    // Now, ensure that the transaction is either rolled back or committed before
    // the function ends
    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p)
        } else if err != nil {
            log.Printf("An error occurred: %v", err)
            if err := tx.Rollback(); err != nil {
                log.Printf("Rollback failed, error: %v", err)
            }
        } else {
            if err := tx.Commit(); err != nil {
                log.Printf("Commit failed, error: %v", err)
            }
        }
    }()

    // Finally, run the function and return the result
    err = txFunc(tx)
    return err
}

这在大多数情况下效果很好。但是,我注意到由于超时、无服务器暂停、超出 IO 限制等原因而发生的许多错误;如:

Login error: mssql: Database 'my-db' on server 'myserver.database.windows.net' is not currently available. Please retry the connection later. If the problem persists, contact customer support, and provide them the session tracing ID of '{SOME_GUID}'.

我想通过某种退避来处理这些问题,而不仅仅是失败。但是,要做到这一点,我需要能够以某种方式解释错误。但是,返回的错误都具有*errors.errorString. 我试过用 usingAs(error, interface{})检查错误是否是 amssql.Error而不是,所以我不确定如何处理它。如何确定这些错误的原因是什么?

4

1 回答 1

1

您可以尝试使用类型断言将您得到的错误转换为此处定义的错误

err:=//your operation that returns an error
//check and convert the error to a MSSQL error with more context
if msSQLErr,ok:=err.(mssql.Error);ok{
   if msSQLErr.SQLErrorNumber() == someRetryableErrorCode{
      //custom retry logic...
   }
}

或者,您可以使用错误。如下

var msSQLErr mssql.Error
if errors.As(err,&msSQLErr){
   if msSQLErr.SQLErrorNumber() == someRetryableErrorCode{
      //custom retry logic...
   }
}

更新:不幸的是,该库似乎没有包装底层错误,因此您不能使用errors.Is或errors。至于一些错误,例如网络相关错误,因此您必须自己使用类似字符串的东西来匹配错误字符串.包含

于 2021-02-27T03:22:12.087 回答