如何合并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
相关产品推荐
相关产品推荐

