go - 无法识别同步中的错误。一旦使用

标签 go concurrency

我正在开设有关 Golang 的在线类(class)。以下代码片段作为滥用 sync.Once 的示例出现在类(class) Material 中:

var (
    once sync.Once
    db   *sql.DB
)

func DbOnce() (*sql.DB, error) {
    var err error
    once.Do(func() {
        fmt.Println("Am called")
        db, err = sql.Open("mysql", "root:test@tcp(127.0.0.1:3306)/test")
        if err != nil {
            return
        }
        err = db.Ping()
    })
    if err != nil {
        return nil, err
    }
    return db, nil
}

据推测,以上是 SQL 连接管理器的错误实现。我们,学生,要自己找出错误,我正在努力解决这个问题。代码即使并行运行也能正常运行。我是这样使用它的:

func main() {
    wg := sync.WaitGroup{}
    wg.Add(10)

    for i := 0; i < 10; i++ {
        go (func() {
            db, err := DbOnce()
            if err != nil {
                panic(err)
            }

            var v int
            r := db.QueryRow("SELECT 1")
            err = r.Scan(&v)
            fmt.Println(v, err)

            wg.Done()
        })()
    }

    wg.Wait()
}

我知道这里不鼓励家庭作业问题,所以我不要求完整的解决方案,只是提示就可以了。错误是否与并发有关(即我需要在特定的并发上下文中运行它)?是不是具体使用了sql.Open?

最佳答案

db 变量的初始化正常。问题在于返回的错误。

如果您第一次调用 DbOnce() 并且打开数据库连接失败,将正确返回该错误。但是后续调用呢? db初始化代码不会再次运行,所以可能返回nil db,由于没有运行初始化代码,默认值返回 err 变量,这将是 nil。综上所述,初始化错误丢失,不再报。

一个解决方案是在连接失败时停止应用程序(在第一次调用时)。另一种选择是将初始化错误与 db 一起存储在包级变量中,并从 DbOnce() 返回它(并且不为此使用局部变量)。前者的优点是您不必处理从 DbOnce() 返回的错误,因为它甚至不必返回错误(如果有错误,您的应用程序将终止)。

后者可能是这样的:

var (
    once  sync.Once
    db    *sql.DB
    dbErr error
)

func DbOnce() (*sql.DB, error) {
    once.Do(func() {
        fmt.Println("Am called")
        db, dbErr = sql.Open("mysql", "root:test@tcp(127.0.0.1:3306)/test")
        if dbErr != nil {
            return
        }
        dbErr = db.Ping()
    })
    return db, dbErr
}

关于go - 无法识别同步中的错误。一旦使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71902034/

相关文章:

mysql - 原子读取和条件创建或更新

concurrency - 如何在hive中同时提交多个查询

java - 在使用 java.util.concurrent 类时,我应该同步以避免可见性问题吗?

java - 线程没有被终止;陷入循环

go - 返回的参数太多

google-app-engine - GAE Go - 如何处理 ErrConcurrentTransaction 数据存储事务错误

git - 从私有(private)存储库获取依赖项的正确方法

networking - Go package syscall conn.Read() 是非阻塞的,导致 CPU 使用率高

go - 如何确定包源文件的目录

java - 用 Java 编写线程安全的模块化计数器