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

Go循环中使用Goroutine执行数据库插入是否为最佳实践?

你的Goroutine数据库插入方式并非最佳实践

先纠正一个关键问题:你测试得到的427ns耗时完全不反映真实的数据库插入耗时——你的代码只是启动了所有协程就结束计时了,根本没等待所有数据库插入操作完成。这个时间只是创建并启动协程的开销,不是真正的业务执行时间,实际所有插入任务可能还在后台跑,你根本没统计到。

下面说为什么这种方式不是最佳实践,以及正确的思路:

核心问题

  1. 无等待的异步任务导致统计失真
    你没有用sync.WaitGroup这类工具等待所有协程执行完毕,所以计时结果毫无参考价值,甚至会误导你以为并发带来了巨大性能提升,实际上只是没等任务做完。

  2. 数据库资源过载风险
    如果save_in_db每次创建新连接,大量协程同时发起连接请求会直接打满数据库的连接数上限,触发报错;即使复用连接池,过多并发插入会导致数据库内部锁竞争加剧、IO瓶颈凸显,反而比串行插入更慢,甚至出现超时、死锁。

  3. 错误完全不可控
    你的代码没有处理save_in_db可能出现的任何错误(比如主键冲突、数据库连接失败),协程内的错误或panic会被静默忽略,你根本不知道哪些数据插入失败,排查问题无从下手。

正确的批量插入方案

方案1:优先用数据库原生批量插入(最优)

对于少量数据(比如你说的5条),直接用数据库的批量插入语法,把所有数据拼成一条SQL执行,这是性能最高、最可靠的方式:

// 准备批量DTO
var dtos []product_dto
for _, j := range items {
    dtos = append(dtos, prepare_dto(j))
}

// 执行批量插入,比如MySQL的语法:INSERT INTO table (...) VALUES (...), (...), ...
err := batch_save_in_db(dtos)
if err != nil {
    // 统一处理错误
}

这种方式只需要一次数据库请求,避免了多次连接开销,数据库内部也能高效处理批量写入,性能远优于开多个协程。

方案2:并发插入(仅适用于超大量数据)

如果数据量极大,单条批量SQL过长(超过数据库限制),可以用带并发限制的协程执行插入,同时做好等待和错误处理:

import (
    "sync"
    "log"
    "fmt"
)

func batchInsert(items []product_object) error {
    var wg sync.WaitGroup
    // 限制并发数,比如最多10个协程同时执行,根据数据库连接池大小调整
    semaphore := make(chan struct{}, 10)
    errChan := make(chan error, len(items))

    for _, j := range items {
        wg.Add(1)
        semaphore <- struct{}{} // 获取并发许可

        go func(item product_object) {
            defer wg.Done()
            defer func() { <-semaphore }() // 释放并发许可

            obj := prepare_dto(item)
            if err := save_in_db(obj); err != nil {
                errChan <- err
                log.Printf("插入产品ID:%d失败: %v", item.id, err)
            }
        }(j)
    }

    // 等待所有协程完成
    wg.Wait()
    close(errChan)

    // 收集错误
    var errs []error
    for err := range errChan {
        errs = append(errs, err)
    }

    if len(errs) > 0 {
        return fmt.Errorf("共%d条插入失败: %v", len(errs), errs)
    }
    return nil
}

这种方式既利用了并发提升效率,又避免了无限制并发压垮数据库,同时能收集所有错误。

总结

  • 数据量小(几十/几百条):直接用批量插入,不要用协程,简单高效。
  • 数据量极大:用带并发限制的协程+等待机制+错误收集,同时根据数据库连接池大小调整并发数。
  • 绝对不要像你原来那样直接开N个协程就不管了,既无法统计真实耗时,又会带来各种稳定性问题。

内容的提问来源于stack exchange,提问作者Sowmya Ravichandran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 15:15:10