首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sqlx.Next和sqlx.StructScan对并发使用是否安全?

sqlx.Next和sqlx.StructScan对并发使用是否安全?
EN

Stack Overflow用户
提问于 2020-07-13 20:57:50
回答 1查看 433关注 0票数 1

我在一个MySQL数据库中有一个大表,我正试图尽可能高效地读取该表。我正在考虑通过添加多个工作人员来加快代码的速度,但是,当我这样做时,在运行它的一开始就会收到封送错误(只在开始时),它看起来如下所示:

{"caller":"mysql.go:repository.(*MySQLRepo).GetNextBatch#428",“

”:“DBGetRecordException:无法封送插曲注释: sql:扫描列索引4上的错误,名称"created_at":不支持扫描,将driver.Value类型[]uint8存储到*time.Time类型”,“DBGetRecordException”:“错误”,"ts":"2020-07-13T20:42:03.9621 658Z"}

如果我从ImportLegacyComments中删除工作代码并正常循环它,我就不会理解这是错误。sqlx.next和sqlx.StructScan对多线程是否安全,如果不安全,是否有其他安全的方法?

代码语言:javascript
复制
import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jmoiron/sqlx"
)

type BatchResult struct {
    rows *sqlx.Rows
}

func (m *MySQLRepo) GetNextBatch(b *BatchResult) ([]model.EpisodeComment, error) {
    var episodeComments []model.EpisodeComment
    for i := 0; i < 1000 && b.rows.Next(); i++ {
        var episodeComment model.EpisodeComment
        err := b.rows.StructScan(&episodeComment)
        if err != nil {
            return nil, err
        }
        episodeComments = append(episodeComments, episodeComment)
    }
    return episodeComments, nil
}
func (m *MySQLRepo) FetchAllEpisodeComments() (*BatchResult, error) {
    rows, err := m.db.Queryx("SELECT * FROM episode_comment")
    if err != nil {
        return nil, err
    }
    return &BatchResult{
        rows: rows,
    }, nil
}

func (svc *ImportService) ImportLegacyComments(ctx context.Context) error {
    batchResult, err := svc.legacyCommentsRepo.FetchAllEpisodeComments()
    var wg sync.WaitGroup
    processor := func() {
        comments, err := svc.legacyCommentsRepo.GetNextBatch(batchResult)
        if err != nil {
            svc.logger.Error(err)
        }
        for len(comments) > 0 {
            comments, err = svc.legacyCommentsRepo.GetNextBatch(batchResult)
            if err != nil {
                svc.logger.Error(err)
            }
            svc.logger.Info("batch", "completed 1000")
        }
        wg.Done()
    }

    for i := 0; i < 20; i++ {
        go processor()
        wg.Add(1)
    }

    wg.Wait()

    return err
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-07-13 22:47:03

sqlx.Nextsqlx.StructScan对于并发使用是不安全的。

如果您为代码组合了一个简单的单元测试,并使用竞争检测器go test -race运行它,它将在"database/sql".Rows结构的未导出字段上报告一个争用条件:

代码语言:javascript
复制
Write at 0x00c00000e080 by goroutine 22:
  github.com/lib/pq.(*rows).Next()
      /Users/blackgreen/go/pkg/mod/github.com/lib/pq@v1.2.0/conn.go:1464 +0x8ec
  ...

Previous read at 0x00c00000e080 by goroutine 20:
  database/sql.(*Rows).Scan()
      /usr/local/go/src/database/sql/sql.go:3041 +0x2fa
  ...

如果我们去找出竞争检测器抱怨的是哪个字段,我们就可以看到一个反对并发使用的指示是正确记录的:

代码语言:javascript
复制
    // lastcols is only used in Scan, Next, and NextResultSet which are expected
    // not to be called concurrently.
    lastcols []driver.Value
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62884143

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档