无法识别 sync.Once 用法中的错误
Cannot identify an error in sync.Once usage
我正在做一个关于 Golang 的在线课程。以下代码片段在课程 material 中作为滥用 sync.Once
:
的示例
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
变量的初始化正常。问题在于 returned 错误。
如果您第一次调用 DbOnce()
并且打开数据库连接失败,该错误将被 return 正确编辑。但是后续调用呢? db
初始化代码不会再次 运行,因此 nil
db
可能会被 returned,并且由于初始化代码不是 运行 ,err
变量的默认值为 returned,即 nil
。综上所述,初始化错误丢失,不再报
一个解决方案是在连接失败时停止应用程序(在第一次调用时)。另一种选择是将初始化错误与 db
和来自 DbOnce()
的 return 一起存储在包级变量中(并且不为此使用局部变量)。前者的优点是您不必处理 return 来自 DbOnce()
的错误,因为它甚至不必 return 错误(如果有错误,您的应用将终止)。
后者可能是这样的:
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
}
我正在做一个关于 Golang 的在线课程。以下代码片段在课程 material 中作为滥用 sync.Once
:
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
变量的初始化正常。问题在于 returned 错误。
如果您第一次调用 DbOnce()
并且打开数据库连接失败,该错误将被 return 正确编辑。但是后续调用呢? db
初始化代码不会再次 运行,因此 nil
db
可能会被 returned,并且由于初始化代码不是 运行 ,err
变量的默认值为 returned,即 nil
。综上所述,初始化错误丢失,不再报
一个解决方案是在连接失败时停止应用程序(在第一次调用时)。另一种选择是将初始化错误与 db
和来自 DbOnce()
的 return 一起存储在包级变量中(并且不为此使用局部变量)。前者的优点是您不必处理 return 来自 DbOnce()
的错误,因为它甚至不必 return 错误(如果有错误,您的应用将终止)。
后者可能是这样的:
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
}