MST

星途 面试题库

面试题:Go闭包与资源管理的复杂应用

在一个需要频繁创建和销毁数据库连接的Go应用程序中,使用闭包来管理数据库连接资源。要求不仅要确保连接的正确获取与释放,还要处理可能出现的并发安全问题,同时在高并发下保证性能。请详细阐述你的设计方案,并给出关键代码片段。
19.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 设计方案
    • 使用sync.Pool来管理数据库连接资源。sync.Pool是Go语言提供的一个对象池,它能在高并发场景下高效地复用对象,减少内存分配和垃圾回收压力。
    • 利用闭包来封装获取和释放连接的逻辑,确保连接的正确使用和并发安全。
    • 在获取连接时,从sync.Pool中获取,如果池为空则创建新连接。
    • 在释放连接时,将连接放回sync.Pool中,而不是直接销毁。
  2. 关键代码片段
package main

import (
    "database/sql"
    "fmt"
    "sync"

    _ "github.com/go - sql - driver/mysql" // 假设使用MySQL,根据实际情况调整
)

var (
    dbPool     *sql.DB
    connectionPool sync.Pool
)

func init() {
    var err error
    dbPool, err = sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database_name")
    if err != nil {
        panic(err.Error())
    }
    // 初始化连接池
    connectionPool = sync.Pool{
        New: func() interface{} {
            conn, err := dbPool.Conn(nil)
            if err != nil {
                panic(err.Error())
            }
            return conn
        },
    }
}

// 获取连接的闭包
func getConnection() func() (*sql.Conn, error) {
    return func() (*sql.Conn, error) {
        conn := connectionPool.Get().(*sql.Conn)
        // 检查连接是否可用,如果不可用则重新获取
        err := conn.Ping()
        if err != nil {
            conn.Close()
            conn = connectionPool.Get().(*sql.Conn)
        }
        return conn, nil
    }
}

// 释放连接的闭包
func releaseConnection() func(conn *sql.Conn) {
    return func(conn *sql.Conn) {
        connectionPool.Put(conn)
    }
}

在实际使用中,可以这样调用:

func main() {
    getConn := getConnection()
    releaseConn := releaseConnection()
    conn, err := getConn()
    if err != nil {
        fmt.Println("获取连接失败:", err)
        return
    }
    defer releaseConn(conn)
    // 执行数据库操作
    rows, err := conn.Query("SELECT * FROM some_table")
    if err != nil {
        fmt.Println("查询失败:", err)
        return
    }
    defer rows.Close()
    // 处理查询结果
    for rows.Next() {
        // 处理逻辑
    }
}