如何正确实现多复制数据库优先响应的query查询函数?
问题分析与解决方案
你的代码存在几个关键问题:
- 定义的三个
Conn1/Conn2/Conn3类型的channel没有任何数据写入,select会一直阻塞,程序永远不会返回结果 - 逻辑顺序错误:应该是先并发调用所有连接的查询方法,再通过channel接收结果,而非等待channel传递连接对象后再执行查询
- 硬编码连接类型,没有利用传入的
conns切片,无法适配任意数量的数据库连接
正确实现方式
核心思路是通过goroutine并发执行所有数据库查询,用channel收集结果,再通过select获取第一个返回的结果:
func query(conns []Conn, query string) Result { // 创建带缓冲的channel,避免goroutine泄露(缓冲数等于连接数,确保所有结果都能被接收) resCh := make(chan Result, len(conns)) // 遍历所有连接,并发执行查询 for _, conn := range conns { go func(c Conn, q string) { res := c.DoQuery(q) resCh <- res }(conn, query) } // 接收第一个返回的结果 return <-resCh }
完整修正后的代码
package main import ( "fmt" "time" ) type Conn interface { DoQuery(query string) Result } type Result struct { Query string ConnName string } type Conn1 struct{} type Conn2 struct{} type Conn3 struct{} func (c Conn1) DoQuery(query string) Result { time.Sleep(1 * time.Second) return Result{Query: query, ConnName: "Conn1"} } func (c Conn2) DoQuery(query string) Result { time.Sleep(2 * time.Second) return Result{Query: query, ConnName: "Conn2"} } func (c Conn3) DoQuery(query string) Result { time.Sleep(3 * time.Second) return Result{Query: query, ConnName: "Conn3"} } func query(conns []Conn, query string) Result { resCh := make(chan Result, len(conns)) for _, conn := range conns { // 传递循环变量副本,避免goroutine引用同一变量的问题 go func(c Conn, q string) { res := c.DoQuery(q) resCh <- res }(conn, query) } // 取第一个返回的结果 return <-resCh } func main() { conns := make([]Conn, 3) conns[0] = Conn1{} conns[1] = Conn2{} conns[2] = Conn3{} res := query(conns, "select * from users") fmt.Println(res) }
关键细节说明
- 带缓冲channel:缓冲大小等于连接数,确保所有goroutine的结果都能被发送,避免未完成的goroutine阻塞泄漏
- goroutine变量传递:必须通过函数参数传递循环变量的副本,否则所有goroutine会复用循环的最后一个变量值
- 简化的结果接收:直接接收
<-resCh即可获取第一个返回的结果,后续结果会暂存在channel缓冲中,程序退出时会自动回收
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

