MST

星途 面试题库

面试题:Go并发程序模块化设计之资源管理

在Go并发程序模块化设计中,假设你有一个模块负责管理数据库连接资源。当多个goroutine并发访问这个模块获取数据库连接时,如何设计才能确保连接的正确分配、使用和释放,以避免资源泄露和竞争问题?请给出关键代码示例及简要说明。
33.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 使用sync.Mutex和连接池
    • 连接池可以有效管理数据库连接,避免频繁创建和销毁连接。
    • sync.Mutex用于保护对连接池的操作,防止竞争。
package main

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

    _ "github.com/lib/pq" // 以PostgreSQL为例,根据实际数据库选择
)

// 定义数据库连接池结构体
type ConnectionPool struct {
    pool    []*sql.DB
    mutex   sync.Mutex
    capacity int
}

// 创建连接池
func NewConnectionPool(capacity int) *ConnectionPool {
    pool := make([]*sql.DB, 0, capacity)
    for i := 0; i < capacity; i++ {
        db, err := sql.Open("postgres", "user=postgres dbname=mydb sslmode=disable")
        if err != nil {
            panic(err)
        }
        pool = append(pool, db)
    }
    return &ConnectionPool{
        pool:    pool,
        capacity: capacity,
    }
}

// 获取连接
func (cp *ConnectionPool) GetConnection() *sql.DB {
    cp.mutex.Lock()
    defer cp.mutex.Unlock()
    if len(cp.pool) == 0 {
        // 可以选择等待连接可用,或者返回错误
        return nil
    }
    conn := cp.pool[0]
    cp.pool = cp.pool[1:]
    return conn
}

// 释放连接
func (cp *ConnectionPool) ReleaseConnection(conn *sql.DB) {
    cp.mutex.Lock()
    defer cp.mutex.Unlock()
    if len(cp.pool) >= cp.capacity {
        // 超出容量时可以选择关闭连接
        conn.Close()
        return
    }
    cp.pool = append(cp.pool, conn)
}
  1. 简要说明
    • ConnectionPool结构体包含一个连接切片pool用于存储数据库连接,mutex用于同步访问连接池,capacity表示连接池的最大容量。
    • NewConnectionPool函数初始化连接池,创建指定数量的数据库连接并添加到池中。
    • GetConnection方法在获取连接时,先锁定mutex,从连接池中取出一个连接并从池中移除,使用defer确保解锁mutex
    • ReleaseConnection方法在释放连接时,同样先锁定mutex,如果连接池未满则将连接放回池中,否则关闭连接。这样设计可以确保在多个goroutine并发访问时,数据库连接能正确分配、使用和释放,避免资源泄露和竞争问题。