You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并Go语言中的两个函数?求整洁Go代码实现方法

合并Go数据库操作函数的优化方案

嘿,我来帮你搞定这个Go代码合并的事儿!先看看你给出的这段db_execute函数,咱们一步步来优化合并~

首先,先把你提供的代码规整一下:

func db_execute(sql_cmd string) bool {
    db, err := sql.Open("mysql", mysql_login)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    
    err = db.Ping()
    if err != nil {
        log.Fatal(err)
    }
    
    stmt, err := db.Prepare(sql_cmd)
    if err != nil {
        fmt.Print(err.Error())
    }
    _, err = stmt.Exec()
    if err != nil {
        fmt.Print(err.Error())
        return false
    }
    return true
}

先聊聊现有代码的几个小问题

  • 每次调用都重新创建DB连接,非常浪费资源,Go的sql.DB本身就是连接池,应该初始化一次复用
  • 部分错误用log.Fatal直接退出程序,可能不符合业务场景(比如执行失败不该直接崩掉服务)
  • 函数名用下划线命名,不符合Go的驼峰命名规范
  • 缺少stmt.Close()的defer,可能导致资源泄漏

合并函数的思路:抽离公共逻辑,做通用化处理

假设你要合并的另一个函数是查询类函数(比如db_query),咱们可以把数据库连接、错误处理这些公共部分抽出来,然后写一个支持执行/查询的通用函数,或者拆分出更清晰的专用函数(推荐后者,可读性更高)。

第一步:初始化全局连接池

先在程序启动时初始化一次DB连接池,不用每次调用都创建:

import (
    "database/sql"
    "fmt"
    "log"
    _ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func init() {
    var err error
    // 替换成你的数据库连接字符串
    db, err = sql.Open("mysql", mysql_login)
    if err != nil {
        log.Fatalf("Failed to initialize DB connection: %v", err)
    }

    // 配置连接池参数,按需调整
    db.SetMaxOpenConns(10)  // 最大打开连接数
    db.SetMaxIdleConns(5)   // 最大空闲连接数
    db.SetConnMaxLifetime(300) // 连接存活时间(秒)

    // 验证连接有效性
    if err := db.Ping(); err != nil {
        log.Fatalf("Failed to ping DB: %v", err)
    }
    log.Println("DB connection pool initialized successfully")
}

第二步:拆分/合并为通用操作函数

如果你想把执行和查询合并成一个函数,可以用回调函数来处理查询结果;如果追求可读性,分开写专用函数也很合适。

方案1:拆分清晰的专用函数(推荐)
// Execute 执行无返回结果的SQL(插入/更新/删除)
func Execute(sqlCmd string, args ...interface{}) error {
    stmt, err := db.Prepare(sqlCmd)
    if err != nil {
        return fmt.Errorf("prepare statement failed: %w", err)
    }
    defer stmt.Close()

    _, err = stmt.Exec(args...)
    if err != nil {
        return fmt.Errorf("execute statement failed: %w", err)
    }
    return nil
}

// Query 执行查询并通过回调处理结果
func Query(sqlCmd string, resultHandler func(*sql.Rows) error, args ...interface{}) error {
    rows, err := db.Query(sqlCmd, args...)
    if err != nil {
        return fmt.Errorf("query failed: %w", err)
    }
    defer rows.Close()

    // 调用传入的回调函数处理行数据
    if err := resultHandler(rows); err != nil {
        return err
    }

    // 检查遍历过程中是否出现错误
    if err := rows.Err(); err != nil {
        return fmt.Errorf("rows iteration failed: %w", err)
    }
    return nil
}

使用示例:

// 执行插入操作
err := Execute("INSERT INTO users(name, age) VALUES(?, ?)", "Bob", 28)
if err != nil {
    log.Printf("Insert failed: %v", err)
}

// 执行查询并处理结果
err = Query("SELECT id, name FROM users WHERE age > ?", func(rows *sql.Rows) error {
    for rows.Next() {
        var id int
        var name string
        if err := rows.Scan(&id, &name); err != nil {
            return fmt.Errorf("scan row failed: %w", err)
        }
        fmt.Printf("User ID: %d, Name: %s\n", id, name)
    }
    return nil
}, 25)
if err != nil {
    log.Printf("Query failed: %v", err)
}
方案2:合并为单一通用函数

如果你坚持要合并成一个函数,可以通过判断回调是否为空来区分执行/查询:

// DBDo 通用数据库操作函数,支持执行(无回调)和查询(带回调)
func DBDo(sqlCmd string, resultHandler func(*sql.Rows) error, args ...interface{}) error {
    // 无回调则执行无返回结果的SQL
    if resultHandler == nil {
        stmt, err := db.Prepare(sqlCmd)
        if err != nil {
            return fmt.Errorf("prepare statement failed: %w", err)
        }
        defer stmt.Close()

        _, err = stmt.Exec(args...)
        if err != nil {
            return fmt.Errorf("execute statement failed: %w", err)
        }
        return nil
    }

    // 有回调则执行查询并处理结果
    rows, err := db.Query(sqlCmd, args...)
    if err != nil {
        return fmt.Errorf("query failed: %w", err)
    }
    defer rows.Close()

    if err := resultHandler(rows); err != nil {
        return err
    }

    if err := rows.Err(); err != nil {
        return fmt.Errorf("rows iteration failed: %w", err)
    }
    return nil
}

使用示例:

// 执行更新操作
err := DBDo("UPDATE users SET age = ? WHERE name = ?", nil, 29, "Bob")
if err != nil {
    log.Printf("Update failed: %v", err)
}

// 执行查询操作
err = DBDo("SELECT name, age FROM users", func(rows *sql.Rows) error {
    for rows.Next() {
        var name string
        var age int
        if err := rows.Scan(&name, &age); err != nil {
            return fmt.Errorf("scan failed: %w", err)
        }
        fmt.Printf("Name: %s, Age: %d\n", name, age)
    }
    return nil
})
if err != nil {
    log.Printf("Query failed: %v", err)
}

额外的优化建议

  • 用%w包装错误,保留错误链,方便后续用errors.Is/errors.As排查问题
  • 避免直接用log.Fatal,除非是启动时的致命错误,业务逻辑里应该返回错误让调用方处理
  • 尽量使用参数化查询(?占位符),防止SQL注入

内容的提问来源于stack exchange,提问作者Lucian Blaga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:17:41