Параллельное выполнение gorm запросов в golang

У меня есть 2 сущности:

type Service struct {
    ID   string
    Name string
}

type ConnectedService struct {
    ID        int
    ServiceID string
    Service   Service
}

Я хочу, используя gorm.io/gorm v2, получить доступ к связанной сущности Service, получая ConnectedService.

Проблема в том, что если выполнять параллельно (в go-рутинах) несколько запросов, на получение ConnectedService, то вылетает ошибка, если делать последовательно, ошибки нет:

ERROR: invalid reference to FROM-clause entry for table "connected_services" (SQLSTATE 42P01)
[4.020ms] [rows:0] SELECT "connected_services"."id","connected_services"."service_id" FROM "connected_services" Service WHERE "connected_services"."id" = 3 ORDER BY "connected_services"."id" LIMIT 1
FATA[0000] ERROR: invalid reference to FROM-clause entry for table "connected_services" (SQLSTATE 42P01) 

Это связанно с тем, что gorm v2 использует: Method Chain Safety/Goroutine Safety. Вот что пишут на оф. сайте:

To reduce GC allocs, GORM V2 will share Statement when using method chains, and will only create new Statement instances for new initialized *gorm.DB or after a New Session Method, to reuse a *gorm.DB, you need to make sure it just after a New Session Method, for example:

Я пробовал делать запросы с разными контекстами и ничего не получается.

Так же, если убрать .Joins("Service"), то работает и синхронно, и асинхронно.

Запросы выполняю так:

type Repository struct { db *gorm.DB }
func (r *Repository) GetConnectedService(id int) (*ConnectedService, error) {
    cs := &ConnectedService{}
    if err := r.db.WithContext(context.Background()).Joins("Service").First(cs, id).Error; err != nil {
        return nil, err
    }
    return cs, nil
}

Инициализация дб и репозитория:

func main() {
    dsn := fmt.Sprintf("host=localhost port=5433 user=guest password=guest dbname=mydb sslmode=disable")
    db, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    repo := &Repository{db: db}
    . . .
}

Вызов делаю так:

import (
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

func main() {
    . . .
    for i := 1; i < 10; i++ {
        go func(i int) {
            cs, err := repo.GetConnectedService(i)
            if err != nil {
                logrus.Errorf("get connected service: %s", err.Error())
                return
            }
            logrus.Printf("%+v", cs)
        }(i)
    }
    . . .
}

Without <.Joins("Service")> everything works fine, but as soon as we add this, an error crashes.


Ответы (0 шт):