// У нас есть метод получения информации о товарах, данный метод вызывается очень часто // есть ли проблемы в этом коде и как исправить? база данных postgress func (r *ProductRepository) GetProductDetails(ctx context.Context, productIDs []int) []Product { products := make([]Product, 0, len(productIDs)) for _, id := range productIDs { go func(id int) { var p Product query := "SELECT name, price, description FROM products WHERE id = $1" err := r.db.QueryRowContext(ctx, query, id).Scan(&p.Name, &p.Price, &p.Desc) if err != nil { r.logger.Error("error get product", "err", err) return } products = append(products, p) }(id) } return products }
Ответ от нейросети
sobes.tech AI
В представленном коде есть несколько проблем:
-
Горутины и конкурентный доступ к срезу
products— несколько горутин одновременно вызываютappendк одному срезу без синхронизации, что приводит к гонкам данных и возможным паникам. -
Отсутствие ожидания завершения горутин — функция возвращает
productsсразу после запуска горутин, не дожидаясь их завершения, поэтому результат всегда будет пустым или неполным. -
Много отдельных запросов к базе — для каждого
productIDвыполняется отдельный запрос, что неэффективно.
Как исправить:
-
Использовать один запрос с оператором
WHERE id IN (...), чтобы получить все продукты за один вызов. -
Если нужно параллельно, использовать синхронизацию (например,
sync.WaitGroupи мьютекс) для безопасного доступа к срезу.
Пример исправленного кода с одним запросом:
func (r *ProductRepository) GetProductDetails(ctx context.Context, productIDs []int) ([]Product, error) {
if len(productIDs) == 0 {
return nil, nil
}
query := `SELECT id, name, price, description FROM products WHERE id = ANY($1)`
rows, err := r.db.QueryContext(ctx, query, pq.Array(productIDs))
if err != nil {
return nil, err
}
defer rows.Close()
var products []Product
for rows.Next() {
var p Product
if err := rows.Scan(&p.ID, &p.Name, &p.Price, &p.Desc); err != nil {
return nil, err
}
products = append(products, p)
}
return products, rows.Err()
}
Такой подход уменьшит нагрузку на базу и устранит проблемы с конкурентным доступом.