В целом всё выглядит не плохо, но будет лучше, если контекст будем принимать на вход. Так же было не плохо отменять транзакцию в случае ошибки, ну и закрывать prepare тоже не помешает. На каждую итерацию цикла вовсе не обязательно содавать свой собственный prepare, достаточно одного
func (db *Requests) StorePhotos(ctx context.Context, photos []Photo) error {
ctx, cancel := context.WithTimeout(ctx, time.Minute*2)
defer cancel()
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
stmnt, err := tx.PrepareContext(ctx, "INSERT INTO photos (id, owner_id, req_id, url) VALUES ($1, $2, $3, $4)")
if err != nil {
return err
}
defer stmnt.Close()
for _, photo := range photos {
if _, err = stmnt.ExecContext(ctx, photo.ID, photo.OwnerID, photo.ReqID, photo.URL); err != nil {
return err
}
}
return tx.Commit()
}