Middle+
// Бізде өнімдер туралы ақпарат алудың әдісі бар, бұл әдіс өте жиі шақырылады // Бұл кодта қандай да бір мәселе бар ма және оны қалай түзетуге болады? PostgreSQL дерекқоры 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("өнімді алу кезінде қате", "err", err) return } products = append(products, p) }(id) } return products }
sobes.tech AI
AI-дан жауап
Көрсетілген кодта бірнеше мәселе бар:
- Параллель түрде
productsкесіндісіне қосу синхрондаусыз — бұл деректердің жарысуына және кесіндінің зақымдалуына әкелуі мүмкін. - Әрбір ID үшін горутиндерді іске қосу, бір уақытта жұмыс істеп жатқан горутиндердің санын бақыламай, бұл дерекқорға шамадан тыс жүктеме түсіруі мүмкін.
- Әдіс нәтижені дереу қайтару үшін горутиндердің аяқталуын күтпейді, сондықтан нәтиже әрқашан бос болады.
Қалай түзету керек:
- Барлық өнімдерді бір шақыруда алу үшін
INоператорымен бір SQL сұрауын пайдалану тиімдірек және оңайырақ. - Егер параллельді қажет болса,
sync.WaitGroupжәне мьютекс пайдалану арқылы кесіндеге қауіпсіз қосу.
Түзетілген мысал бір сұраумен:
func (r *ProductRepository) GetProductDetails(ctx context.Context, productIDs []int) ([]Product, error) {
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, nil
}
Мұндай тәсіл дерекқорға жүктемені азайтады және бәсекелестікке қарсы мәселелерді жояды.